I have just published an update to the A Smart Book. Added were 38 pages covering Smart 1.1 – language changes, new controls and RTL additions.
Smart Programmer
Web Development in Pascal
April 27, 2013
April 23, 2013
New in Smart 1.1: Modal Dialogs
Besides the new compiler and a bunch of new components, Smart 1.1 also includes support for modal dialogs. There is also a new demo ModalDialog which shows how to use the new feature. Today I’ll walk you through this demo.
April 20, 2013
New in Smart 1.1: HTML Elements
Smart Mobile Studio 1.1 contains many new controls which I hope to describe in the following days. Today I’ll start with a group of three controls which allow the programmer to insert specific HTML elements (a.k.a. tags) on a Smart form.
April 10, 2013
New in Smart 1.1: Bugs and Omissions
The 1.1 edition generally works very well but there are still few glitches. At the moment I am aware of two problems which can both be fixed by editing the RTL code.
April 02, 2013
New in Smart 1.1: Properties with Anonymous Storage
When a property is backed directly by a field (without a getter and/or a setter) and this field is never accessed directly, the code can be further simplified by dropping the field declaration altogether.
An example of such code would be:
type
TMyClass = class
private
FData: integer;
public
property Data: integer read FData write FData;
end;This code can be simplified to:
type
TMyClass = class
public
property Data: integer;
end;Smart will still create a field inside the TMyClass object, but this field will be aonymous and not accessible directly from the code.
Note: This type of properties cannot be used in external classes and lasses inheriting from the JObject class.
March 25, 2013
New in Smart 1.1: Property Expression
Smart Pascal supports properties just the same as Delphi and Free Pascal do. Properties are supported in classes, records, interfaces and in helpers (helper classes and records). In addition to the standard syntax, Smart Pascal supports property expressions which help you write more compact code.
Property expressions can be used in two ways – by providing a backing storage (typically a field or property containing the data) or by providing a modifying expression (an expression that modifies and returns/stores data). In both cases, property expressions are introduced by an opening parenthesis and ended by a closing parenthesis.
The simplest way to explain the functioning of this language extension is through examples. The following example defines a form containing two labels, W3lblTask and W3lblDetail. The form also defines two properties. Property Task provides access to the W3lblTask.Caption and property Detail provides access to the W3lblDetail.Caption.
type
TToDoListTemplate=class(TW3form)
private
{$I 'ToDoListTemplate:intf'}
protected
procedure InitializeObject; override;
public
property Task: string read (W3lblTask.Caption) write (W3lblTask.Caption);
property Detail: string read (W3lblDetail.Caption) write (W3lblDetail.Caption);
end;Equivalent code in a “classic” style would be quite longer.
type
TToDoListTemplate=class(TW3form)
private
{$I 'ToDoListTemplate:intf'}
function GetDetail: string;
function GetTask: string;
procedure SetDetail(value: string);
procedure SetTask(value: string);
protected
procedure InitializeObject; override;
public
property Task: string read GetTask write SetTask;
property Detail: string read GetDetail write SetDetail;
end;
function TToDoListTemplate.GetDetail: string;
begin
Result := W3lblDetail.Caption;
end;
function TToDoListTemplate.GetTask: string;
begin
Result := W3lblTask.Caption;
end;
procedure TToDoListTemplate.SetDetail(value: string);
begin
W3lblDetail.Caption := value;
end;
procedure TToDoListTemplate.SetTask(value: string);
begin
W3lblTask.Caption := value;
end;In the example above, (W3lblTask.Caption) and (W3lblDetail.Caption) provide a backing storage; a place where the data is stored. We can, however, do more and write a full expression inside the property expression-wrapping brackets. In case of a getter (read access) this expression must return a result and in case of the setter (write access) this expression should be a statement setting the value of the property. The setter can use a pseudo-parameter Value holding the value that was assigned to the property in the code.
I've said should be a statement because the compiler is not really fussy and will handle any expression in the setter. This allows for weird tricks where the assignment to a property produces a side effect.
The second example defines a TAngle record which holds one value (angle) stored in radians and exposes it through two properties, Radians returning the value in radians and Degrees returning the value in degrees. Conversion between radians and degrees is done inside property expressions.
type
TAngle = record
FAngleRad: float;
property Radians: float read FAngleRad write FAngleRad;
property Degrees: float read (Radians/Pi*180) write (Radians := Value/180*Pi);
end;Equivalent code in “classic” style would again be longer.
type
TAngle = record
FAngleRad: float;
functon GetDegrees: float;
procedure SetDegrees(Value: float);
property Radians: float read FAngleRad write FAngleRad;
property Degrees: float read GetDegrees write SetDegrees;
end;
function TAngle.GetDegrees: float;
begin
Result := Radians/Pi*180;
end;
procedure TAngle.SetDegrees(Value: float);
begin
Radians := Value/180*Pi;
end;
March 22, 2013
New in Smart 1.1: Lambdas
Version 1.1 introduced more compact syntax for closures, similar to the C#'s syntax with an extra lambda keyword thrown at the front. Two different types of `lambda` closures are supported -- functions and statements.
Lambda Functions
Lambda functions are used when the code expects an anonymous function and when the code implementing this function is short. The syntax for lambda functions is:
lambda (parameter_list) => expression
The lambda keyword is followed by an optional parameter list, => and an expression returning a result of the appropriate type.
For example, the following code creates an event that is called every five seconds.
var repeater := TW3EventRepeater.Create(
function (Sender: TObject): boolean
begin
Result := MyFunction;
end,
5000);
Anonymous method calls some function in the code and returns its result. (False will trigger another event after the timeout (5000 ms) and True will stop the repeater.)
Let's rewrite this code using a lambda function.
var repeater := TW3EventRepeater.Create(lambda (Sender) => MyFunction, 5000);
As you can see, there's no need to declare the parameter (Sender) type and the function result type; Smart will detect them automatically. Even more, as we don't use the Sender parameter, we can drop the parameter list and use an even shorter form.
var repeater := TW3EventRepeater.Create(lambda => MyFunction, 5000);
Lambda Statements
The statement form is used when you want to put more than one statement inside the lambda. The syntax for lambda statement is:lambda (parameter_list) statement; [statement;] [...]
[statement;]
end
A lambda statement can also implement a function; in that case you should return the result in a normal Delphi way by assigning to a Result pseudo-variable.
Following example sets up a repeater that calls a method MyProc every three seconds.
var repeater := TW3EventRepeater.Create(lambda => MyProc; Result := false; end, 5000);
You can use variables inside a lambda statement, but only if they are declared inline.
Lambdas are an excellent addition to the language, as they provide for a more compact code. For example, in Smart 1.0 the W3Layout unit used the following code:
ResizeChildren(FClientArea.Height, [TAlign.Top, TAlign.Bottom],
function (layout: TLayoutImpl): Variant
begin
Result := layout.GetConfig.GetHeight;
end,
procedure (layout: TLayoutImpl; value: integer)
begin
layout.GetConfig.Height(value);
end);
In Smart 1.1, this was simplified to:
ResizeChildren(FClientArea.Height, [TAlign.Top, TAlign.Bottom],
lambda (layout) => layout.GetConfig.GetHeight,
lambda (layout, value) layout.GetConfig.Height(value) end);
Lambdas are also very helpful when defining event handlers.
W3btnOK.OnClick := lambda Application.HideModal(mrOK); end;