Smart Pascal

From HandWiki

Smart Pascal is a dialect of the Object Pascal programming language that is derived from Delphi Web Script, but is adapted for Smart Mobile Studio, a commercial development suite that generates JavaScript rather than machine code.

Smart Pascal is a RAD (rapid application development) language. It has a library of classes and components. The Smart Pascal compiler is a source-to-source compiler generating server independent applications which are compliant with HTML5. Compiled Smart applications can be executed in any modern HTML5 capable browser. A compiled program is then typically embedded within a DIV container element or alternatively set to occupy the entire display.

The run-time library was specifically built for increased productivity and time-to-market with regards to mobile application development. Smart Pascal reduces development time for JavaScript radically linguistically, by means of Object Pascal and true object oriented programming, and with regards to how the run-time library's class and component system is designed. The RTL interacts with the document object model and JavaScript environment in the same way a native language would interact with an operative system; abstracting common denominators and automating complex tasks.

Smart Pascal is also popular for micro-controller programming Espruino and nodeJS client/server modules.

Background

Smart Mobile Studio was designed by Norwegian Jon Lennart Aasenden and Frenchman Eric Grange. The technology is published by software company Optimale Systemer. The language uses a popular open-source scripting engine called Delphi Web Script (DWScript) for syntax verification and parsing. On 18 May 2012 Optimale Systemer disclosed that it had acquired the rights to a custom code generator written by Eric Grange, the maintainer of Delphi Web Script, from his company Creative IT, France (see article: From OP4JS to Smart Mobile Studio).

Prior to working with Eric Grange, Jon Lennart Aasenden had published several proposals where he outlined his thoughts for a new object pascal compiler; a compiler that would target Javascript and the browser as opposed to x86 or ARM processors. He also presented a video demonstrating an early prototype of the compiler (available on YouTube). He was initially met with heavy criticism from the Delphi and Free Pascal community, but found support in Eric Grange who verified and demonstrated that JavaScript had come of age - and could now be used to build large-scale, serious business applications. Jon Lennart wrote the Smart Pascal run-time library and integrated development environment while Eric Grange perfected the code generator and language improvements.

Prototype

The first prototype (alpha build) was released on 20 December 2011 and the duo quickly began to attract other programmers curious about the new platform. The project also received a full two-page coverage in Blaise Pascal Magazine (issue 31), which helped promote the dialect considerably. As a result, the run-time library and tools grew to include support for advanced technologies like Remobjects SDK and Embarcadero Datasnap - donated to the framework by software developer Andre Mussche. From version 2.0 Smart Pascal supported nodeJS, Web Workers and the Espruino micro-controller platform courtesy of German mathematician and developer Christian Budde.

At the same time, technical author and software architect Primož Gabrijelčič (author of the book Parallel Programming, among other titles) decided to write a book on Smart Pascal: A smart book, which for programming languages is often regarded as a stamp of approval.

The dialect known as Smart Pascal grew out of the mutual co-operation between all these individuals.

Smart vs Flash

The Smart Pascal IDE has some similarities with Adobe Flash in that you essentially build object-oriented, high-speed, modular applications designed to live in a HTML document. The graphical capabilities of the Smart run-time library are more than up to the task of replicating some of the features Adobe Flash is famous for - but Smart Pascal is ultimately a toolkit for creating HTML5 mobile applications. There is very little in terms of visual automation provided by the Smart IDE. Smart Pascal was simply not designed to be a multimedia composer and remains a clear-cut HTML5 development platform for Object Pascal programmers. The learning curve for Smart Pascal is considerably higher than for Adobe ActionScript. Pascal is a language primarily used by engineers.

Visual Smart Pascal applications are based on forms. Separate windows can be populated with controls, and code events can be connected to these to respond to user activity. Smart Mobile Studio does come with a visual form designer and property editor - but the designer is simply an aid for ordinary user-interfaces and lacks any support for visual effects.

On the level of architecture, the Smart Pascal run-time library has full support for advanced graphical expressions, including dynamically created CSS3 styles, "tweening", display redraw synchronization, GPU powered 2D and 3D sprites and WebGL. One could say that Smart Pascal is "something like Flash", but that is where the parallel ends. Linguistically and conceptually these software methodologies are worlds apart. They were built for different things even though they can achieve much the same results. Smart Pascal has one advantage over Flash in that HTML5 applications have no dependencies. A Smart Pascal program does not rely on plugins, browser extensions or third party libraries. But Flash is ultimately more polished, representing over a decade of continuous evolution and multimedia excellence.

Database access

The Smart Pascal run-time library supports all the browser database engines in circulation. Access to these is achieved via classes rather than components, which breaks with how Object Pascal traditionally deals with data. As of this writing, the following engines are supported:

  • WebSQL
  • IndexedDB
  • WebStorage API

The Smart IDE also imports and allows access to Embarcadero DataSnap, which is a remote-data-access framework popular with Delphi and C++ builder. Using these import libraries allows Smart Pascal applications to read, write and update remote datasets. Smart Pascal is itself written in Embarcadero Delphi.

The run-time library includes classes for RemObjects SDK, a remote procedure call framework along the lines of Microsoft RPC. JSON RPC and WebSockets are likewise a part of the class library.

Linguistic differences

Smart Pascal has several differences that clearly separate the dialect from standard Object Pascal:

  • Property expressions
  • Array operations
  • Anonymous methods
  • Anonymous classes
  • Partial classes
  • Lambdas
  • Class variables
  • Limited sets support
  • Lack of generics
  • Limited RTTI

Property expressions

In Object Pascal a property is an exposed value that can either be linked to a class-field or a class-member method. This is the traditional way of exposing a value property, where the consumer of the property is abstracted from the reader and writer logic. The consumer does not know if the property is explicitly linked to a field or a writer method.

Smart Pascal has full support for the older paradigm but introduces a technique called "property expressions". It basically allows you to program reader and writer logic as a part of property declarations. This is completely unheard of under traditional Object Pascal, but common in other languages like C# and Objective-C.

In classical Object Pascal you could write something like this:

Type
TMyObject = Class( .. )
private
  FSubObj: TNameData;
protected
  function getFirstName:String;
  procedure setFirstName(value:String);
published
  Property FirstName:String read getFirstName write setFirstName;
end;

function TMyObject.getFirstName:String;
begin
  result:=FSubObj.FirstName;
end;

procedure TMyObject.setFirstName(value:String);
begin
  FSubObj.FirstName:=Value;
end;

Using Smart Pascal with property expressions, you can omit the getFirstName() and setFirstName() stubs - and implement the logic as part of the property declaration itself:

Property FirstName:String
              read ( FSubObject.FirstName )
              write ( FSubObject.FirstName );

Property expressions is especially handy for classes with child objects. If a class exposes sub objects (object lists) you had, prior to generics, to write a lot of the same code over and over again, wrapping already existing code in a list object—which for complex class hierarchies reduces execution speed with unnecessary bloat. This has changed for the better with the introduction of generics, but you still have to isolate reader and writer logic in distinct class members. Under Smart Pascal this is elegantly achieved using arrays:

TMyClass = class
   private
      FList : array of TElement;
   public
      property Items[i: Integer] : TElement read (FList[i]) 
                                            write (FList[i]); default;
      property Count : Integer read (FList.Length);
end;

The technique greatly simplifies number conversion, which can in some cases be done directly in the declaration:

TMyAngle = record
   private
      FAngle : Float;
   public
      property Radians : Float read FAngle write FAngle;
      property Degrees : Float read (RadToDeg(FAngle)) 
                               write (FAngle:=DegToRad(Value));
end;

Array operations

Array operations were added to the Smart Pascal syntax to better adapt to JavaScript. Since JavaScript has no concept of pointers or direct memory access, all attempts at dealing with lists, linked lists etc. in the traditional way would cause a massive speed penalty. So where you under Delphi or Free Pascal would allocate a TList or TObjectList instance - Smart Pascal achieves better performance and identical functionality using ordinary arrays. All arrays support a complete set of operations, regardless of datatype, for inserting, removing, sorting and otherwise manipulate the content.

Where under vanilla Object Pascal you would write:

Procedure TMyObject.AddItem(aValue:Integer);
var
  mLen: Integer;
Begin
  mLen:=length(FMyArray);
  setLength(FMyArray,mLen +1);
  FMyArray[mLen]:=Vaue;
end;

Smart Pascal has this functionality "built-in" for all arrays, as long as the datatypes match. When you combine this with property expressions, the result is a powerful and alternative way of achieving the same with less resources and more speed than generics or traditional Object Pascal:

FMyArray.add(aValue);

As of this writing, the following operations can be performed on all array types:

  • Add
  • Clear
  • Copy
  • Count
  • Delete
  • High
  • Low
  • IndexOf
  • Insert
  • Length
  • Map
  • Peek
  • Pop
  • Push
  • Remove
  • Reverse
  • SetLength

The Peek(), Pop(), Push() method are typically used with FILO (first in, last out) and FIFO (first in, first out) stack objects. Smart Pascal has no need for classes like TObjectlist, TList, TStringlist and TStack (these are provided by the run-time library for legacy support with Delphi's Visual Component Library only).

Anonymous methods

Like property expressions and array operations, anonymous methods was introduced in Smart Pascal as a means to improve compatibility with JavaScript. Both Delphi and Free Pascal support anonymous methods, but Smart Pascal has one advantage over these native compilers. Under native Pascal (compilers that produce executable machine code), you have class procedures and ordinary procedures. The only difference between these two is that if you want to reference the first (class method) you must postfix the declaration with "of object". This way of referencing a class method is typically used for event declarations.

An event is declared thus in ordinary Object Pascal:

Type
TMyEventType = procedure (sender:TObject;const value:Integer) of object;

If you omit the "of object" postfix, the reference can only be used on procedures and functions on unit level. The compiler does not allow you to reference an object method without "of object" being clearly defined.

Smart Pascal does not have this distinction. There is no "of object" in the Smart dialect; anonymous methods can be applied on a wider scale than under native Object Pascal, including object based events and callback handlers.

Under Smart Pascal the example below is perfectly valid and compiles without any problems:

Constructor TMyPanel.Create(AOwner:TW3Component);
Begin
  Inherited Create(AOwner);
  FiPhoneHeader:=TW3HeaderControl.Create(self);
  FiPhoneHeader.Backbutton.onClick := Procedure (sender:TObject)
         Begin
            w3_callback( procedure ()
                    begin
                       showmessage('You clicked the back button 2 seconds ago');
                    end, 2000);
         end;
end;

Anonymous classes

In traditional Object Pascal, all classes inherit from a root type called TObject. This was also the case for Delphi Web Script, from which Smart Pascal evolved. To better be able to import classes written in Javascript—which is extremely important to providing full support for the DOM (document object model) and the full spectrum of JavaScript modules—dependency on TObject as the root of all class types had to be altered.

Eric Grange introduced anonymous classes in Smart Pascal starting from version 1.0, which meant that Smart Pascal was now able to directly import and make use of external classes. This allows the user to simply define a class as external, and classes written in JavaScript that match the interface can thus be created and used alongside those written in Pascal. This is achieved by allowing objects to be rooted from nothing (i.e.: no pre-defined constructor logic and behavior).

JCustomEventInit = class external 'CustomEventInit' (JEventInit)
      detail : Variant
   end;

   JEventTarget = class external 'EventTarget'
      procedure addEventListener(aType : String; callback : JEventListener; capture  : Boolean = false);
      procedure removeEventListener(aType : String; callback : JEventListener; capture  : Boolean = false);
      function  dispatchEvent(event : JEvent) : Boolean;
   end;

Anonymous classes can also be used as lightweight objects (without the external keyword), more akin to records (custom datatypes in other languages) since it does not include the life-cycle management provided by TObject.

Partial classes

Partial classes is yet a feature that has not made it into the Object Pascal standard. It basically means that the full declaration and implementation of a class or record type can be spread over multiple source-files. You can also pre-compile one part while you leave the other part open for implementation by others. This is the case for Mono C# under iOS for instance, where the pre-compiled application controller is expected to be completed by the framework user.

Partial classes is a very helpful feature when deployed with care. It is especially handy for large class hierarchies that target different models. Depending on the model set by the programmer, the implementation of certain features differs according to the source-files included.

Smart Pascal supports two declaration formats of partial classes. The RemObjects Oxygene Pascal syntax, and also the more intuitive "type mytype = partial class(ancestor type)" variation. Partial classes are used throughout the Smart Pascal run-time library:

TW3CustomControl = partial class(TW3MovableControl)
  private
    FAngle: Float;
    FScrollInfo: TW3ScrollInfo;
    FClassNames: TW3CSSClassStyleNames;
    FFont: TW3ControlFont;
    ...
    ...

Lambdas

Lambdas is an extremely handy feature that, like partial and anonymous classes, is not yet a part of classical object pascal. The Smart Pascal syntax supports several kind of lambdas, which is pretty handy when writing asynchronous code.

For instance, the following closure:

var repeater := TW3EventRepeater.Create(
  function (Sender: TObject): boolean
  begin
    Result := MyFunction;
  end,
 5000);

may be written with a lambda:

var repeater :=
  TW3EventRepeater.Create(lambda => MyFunction, 5000);

Lambda statements (i.e. "procedure" kind of closures) can be written as such:

btnOK.OnClick := lambda Application.HideModal(mrOK); end;

Class variables

Class variables basically means that you can define a variable (or multiple variables) in a class that can be altered regardless of an instance construction. This is a handy technique for setting conditions before an object is created from the class prototype.

TMyClass = Class(TObject)
  Public
  var driverMode:Integer;
  End;

  TMyClass.driverMode:=1200;

Limited sets support

In Pascal, a set is a collection of elements of same type. The Smart Pascal syntax currently supports only sets of enumerations, with the "in" operator, and "include(aSet, aValue)" or "exclude(aSet, aValue)" methods.

type
  TMySet = set of (msFirst,msSecond,msThird);

var MySet: TMySet;
begin
  // populate set with two states
  MySet := [msFirst,msThird];
  if msFirst in MySet then
    writeln('First');
  exclude(MySet,msFirst);
  if msFirst in MySet then
    writeln('Never Shown');
end;

Lack Of Generics

Smart Pascal does not support generics. The original syntax of Delphi Web Script Smart Pascal derives from was compatible with Delphi 7. Although the DWScript codebase and language has evolved considerably over the past six years, generics represents a monumental change that might require a complete re-write of the entire parser and AST ("abstract symbolic tree" in compiler science) technology.

Lack of generics is tempered by two features of the language:

  • Powerful array support (a convenient replacement to `TList<T>`);
  • `class of` types can be used to instantiate a given `class` instance at runtime (just as with regular object pascal).

Limited RTTI

Run-time type information is in-part supported by DWScript, including the ability to enumerate properties and class members. RTTI is implemented by the Smart Pascal JavaScript compiler, if the "Emit RTTI information" is defined in the Project's Compiler options. Currently only published properties are part of this information.

Once activated, the following class:

type
   TBase = class
      published
         Field : Integer = 1;
   end;

will emit the following RTTI JavaScript object:

var $RTTI = [
	{ T: {ID:TBase}, A: { ClassType: RTTIPropertyAttribute, N: "Field", T: {ID:Number}, C: 3, G: function (s) { return s.Field }, S: function (s,v) { s.Field=v } } }
];

Then you can access this information from code, as described in this article.

Consensus

Smart Pascal is often regarded as a powerful oddity [1] in the world of object pascal. Even though the language supports nearly every syntax feature defined by Embarcadero Delphi, it often breaks or expands on the syntax to introduce radical but effective solutions, that make it more useful for asynchronous programming. As such it promotes concepts borrowed from both JavaScript and Objective-C, mixed with elements from C++, C# and Smalltalk. The result is a flexible and dynamic flavor of Object Pascal that greatly simplifies server-less HTML5 JavaScript development.

Powerful as the dialect is, many traditional Object Pascal programmers regard Smart as a hybrid language, the common objection being that Smart promotes features somewhat alien to the established principles of Object Pascal. Smart supporters argue that this new dialect is necessary for modern software development, and that this is exactly what Object Pascal needs in order to evolve and adapt - pointing to generics as a recent paradigm shift. As such, the supporters argue that the new language does not pose a threat to the long established syntax, but enriches it with proven techniques from more modern languages.

References

Sources

External references