Archive

Archive for August, 2016

Smart Mobile Studio, updates ohoy

August 29, 2016 2 comments

Its been a while since I’ve written much about Smart Mobile Studio. There are many reasons for this, but I figured I could write a bit now so people dont think we are standing still 🙂 So.. whats going on? Lets go through the highlights!

smart

Some of the more advanced demos include a full bytecode compiler written in Smart Mobile Studio. It may seem like overkill, but its a perfect example of just what Smart can deliver!

New team

When you have a small team you can pivot on a dime. There are no board meetings, no finding dates that suits everyone, “vacation” is a foreign word – and you can pretty much jump on ideas and just implement them straight away.

But as software grows in size and complexity, that way of working can cause more challenges than solutions. You have to establish a proper company structure, plan ahead with care, delegate tasks and do chores you may not like.

Also, teams are people. And people change, take on new jobs and move. Without much drama that is the case for us as well — and while the core of the old team is still working on Smart, we had to establish a new team with more members (and board meetings and .. well, you know how it goes).

New RTL structure

The initial RTL was built side by side with the compiler. In the beginning we didnt even have classical functions like Assigned(), so the codebase had a lot of esoteric twists and asm sections that – as the compiler grew in complexity, became redundant and caused hard to track-down bugs. The compiler is now en-par with Delphi in many ways, although without generics; It represents a whole new dialect of pascal. Where Delphi is the absolute top-dog when it comes to Windows desktop applications – tailored from scratch to fit the Windows API, Smart Pascal was made for Javascript and to interact with the javascript virtual machine environment.

But the old structure, while it served us well in knocking out Cordova Phonegap based apps quickly — just had to be refactored at some point. Javascript is Async by nature and trying to “mimic” blocking execution was starting to impact performance, order and even being able to read and understand the code (for users coming from Delphi or Freepascal).

book

Smart Mobile Studio Unleashed will be released before xmas 2016, it explains in great detail everything you need to write controls, work with memory, write services and basically use Smart Mobile Studio to its full potential.

Just think about it: We want to support mobile devices, nodejs client/server, embedded technology, Windows Universal apps and all the exciting gadgets that are coming out with pure JS interfaces. To pull that off you really need all your ducks in order and a clear separation between visual. non visual and hybrid systems must be in place.

We have solved this quite elegantly in my opinion, by the use of namespaces.

You have the system namespace which implements platform independent code (and abstract classes). Then you have the SmartCL visual framework that contains code that targets the DOM and browser. And finally you have the SmartNJ namespace that contains code adapted for NodeJS and headless frameworks. For embedded devices each will have their own namespace (like Arduino), all of them rooted in the platform independent system namespace.

This is an elegant way of solving how you approach the different platforms out there, it has less overhead than the “all in one” VCL type RTL we have fostered so far.

The downside is naturally, like C# coders live with every day, more units. But I have made sure that correlations match 1:1 as much as possible.

So where you find, for example, “system.filesystem.pas”, you will also find a corresponding “smartcl.filesystem.pas” and a “smartnj.filesystem.pas”. So once you know the units in the system namespace, its just a matter of replacing the prefix for the platform you target.

New tech

While re-factoring  whole RTL is more than enough work, we also want to get new tech into Smart Mobile Studio. A unified filesystem has been long coming, and while we have units to access pretty much every nook and crumble Javascript has to offer — a high level interface that is unified is really where my focus is now.

Storing files on mobile devices, in the browser, node or embedded really should be the same. You should write code once and it should work no matter what namespace you target. I want to shield users from some of the Javascript solutions still out there. But people should always have the option to dig into the underlying API.

Databases

Then there is databases. This has really baked my noodle. As mentioned JavaScript is not linear. Its Async by nature, which means writing a concrete API that fits all has been problematic to say the least. But I am happy to say that the code I have implemented is finally rich enough to capture all of them.

grid

The long awaited DB grid. This one handles thousands of records very fast and uses CSS GPU scrolling and effects. As always its skinnable through the stylesheet

But a DB API is just the foundation. NodeJS has drivers for almost all native databases out there, like MSSQL, MariaDB, Oracle and even good old access for that matter. Implementing these under a unified framework takes time — which is also why we needed more people to join the group.

I have covered the most essential, the built in databases supported by the browser, sqlite and also TW3Dataset — this is more than enough for mobile and browser applications. But NodeJS is a whole other ballgame, and that has really been a challenge. Allthough a very rewarding one intellectually. But NodeJS is so massive that we have to build up over time, its impossible for such a small team to deliver high-level classes for all of them in such short time.

Actions

Actions is another factor I have really wanted for a long time. In Delphi and Lazarus this makes programming so much easier, faster and elegant. And writing a Smart version of this was not hard at all. So this is in place — we only need to adjust the property inspector and automatic codegen to take height for action objects.

Tweening

The effect system in Smart is pretty cool. In fact its one of the most powerful CSS GPU based systems out there. No other system makes writing GPU powered effects so easy, yet its one of the least known aspects of Smart Mobile Studio.

scrolling

Momentum scrolling for listboxes and displays is now standard. In fact, the actual scroll code is isolated in components, so you can mix and match the scroll type you like.

The downside of effects that uses hardware, is that they have to run their course. Once started you cant really stop them, or abort the sequence mid-way. This is actually down to the browser, and even though its all defined in the WC3 standards – no browser really implements the stop feature.

To give users an alternative we have implemented a CPU only tweening system. This can be used to tween (morph is also a word used for this) anything from colors to moving elements. But as mentioned, CPU will always be slower than GPU. But with the tweening library in place, used for example in combination with Sprite3d — you have everything you need to write high-speed, silky smooth multimedia and control effects.

Components, not just controls

And yes, finally we have a pure separation between visual and non-visual components. Once established in the IDE you will be able to drag & drop non-visual controls, and we have debated the use of datamodules as well.

Since the VCL/LCL TComponent type inheritance chain is quite fat, we have avoided that. Non visual controls are called widgets, withe TW3Component now inheriting from TW3CustomWidget. This makes the inheritance chain linear – but allows you to safely write non visual components that are universal and dont collide with the namespaces scheme.

This is really cool! For instance listboxes now have a scrollmethod property where you can hook up a non-visual scroll mechanism. Momentum scroll? Row-by-Row scroll? Flat scroll? It makes it so much easier to hook things up.

Where to next?

There are a few company formalities left, but once those are in place we’ll get cracking! I personally cant wait to get going on the new IDE features. And with nodeJS becoming more and more relevant, both for embedded work and Smart devices – I think everyone will agree that it was worth the wait!

And as always — a long, long nose to those that said “it cant be done” 🙂

Lazy Params, again..

August 29, 2016 Leave a comment

Right. A while back I posted an idea I had for extracting name/value pairs from a string. You know, typical “this=that” type parameters. This was just a concept, an idea, a scetch of how I could re-implement coding techniques from Smart Pascal in Delphi.

The point was actually not the name-value pair stuff at all, but rather setting up code in a way that allowed us to extract information on demand, objectively, and then just let the object die out when we dont need it anymore. Things common to C# and JS, but sometimes hard to get right in traditional languages like C++ and Delphi.

Come on you vicious bastard!

Monty Python feelings

Naturally, ideas and concepts are not carved in stone. When you sit down to scetch out a painting – you dont actually produce the complete work. You play around with the idea and flesh out a draft. Sadly this was missunderstood in that post, and I have gotten more than a few comments on it.

As I mentioned in the original post (towards the end), the code did include a few faults. Most notably a missing destructor to kill the dictionary – and also the lack of an interface to get the reference counting working.

It was also pointed out that -since only a string was being managed, it wouldnt actually invoke the destructor as planned.

Well, I think we have exhausted the topic, but I will repeat it one more time: This was just a rough scetch. A concept, and idea. It was not something carved in stone — and like many bloggers I just typed down the idea quickly, taking for granted that people interested in new ideas would add the missing bits without doing through the rough code with a fine tooth comb. Boy was I wrong.

Anyways, here is a working version of the idea. Complete with a padding integer, object isolation and the bare minimum. Place some breakpoints and you can verify that it indeed releases the instances (which is why the destructor for TSourceParameter does nothing but call inherited) as expected. So you can remove the destructor all together, its just there to place a breakpoint.

Just start a new VCL project, drop a button on the form, then copy and replace the form text with the code below. Hopefully this closes the subject once and for all.

Oh, and I would move TSourceParameter into the implementation section of the unit and only expose the interface.

 

unit Unit1;

interface

uses
  System.generics.collections,
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type

  TSourceParameters = Class(TInterfacedObject)
  private
    FLUT: TDictionary<string,string>;
  public
    type

    ISourceParameter = interface
      ['{C6C937DF-50FA-4984-BA6F-EBB0B367D3F3}']
      function Empty: boolean;
      function AsString: string;
      function AsInteger: integer;
      function AsBool: boolean;
      function AsFloat: double;
    end;

    TSourceParameter = Class(TInterfacedObject, ISourceParameter)
    private
      FData:      string;
      __pad:      integer;
    public
      function    Empty:Boolean;
      function    AsString:String;
      function    AsInteger:Integer;
      function    AsBool:Boolean;
      function    AsFloat:Double;
      Constructor Create(Data:String);virtual;
      Destructor Destroy;Override;
    end;

    function    Get(Name:String):ISourceParameter;
    Constructor Create(CommandText:String);virtual;
    Destructor Destroy;Override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//#############################################################################
// TSourceParameters.TSourceParameter
//#############################################################################

Constructor TSourceParameters.TSourceParameter.Create(Data:String);
begin
  inherited Create;
  FData:=trim(Data);
end;

Destructor TSourceParameters.TSourceParameter.Destroy;
begin
  inherited;
end;

function TSourceParameters.TSourceParameter.Empty:Boolean;
begin
  result:=length(FData)<1;
end;

function TSourceParameters.TSourceParameter.AsString:String;
begin
  result:=FData;
end;

function TSourceParameters.TSourceParameter.AsInteger:Integer;
begin
  TryStrToInt(FData,Result);
end;

function TSourceParameters.TSourceParameter.AsBool:Boolean;
begin
  TryStrToBool(FData,Result);
end;

function TSourceParameters.TSourceParameter.AsFloat:Double;
begin
  TryStrToFloat(FData,Result);
end;

//#############################################################################
// TSourceParameters
//#############################################################################

Constructor TSourceParameters.Create(CommandText:String);
var
  mList:  TStringlist;
  x:      Integer;
  mId:    String;
begin
  inherited Create;
  FLUT:=TDictionary<string,string>.Create;

  commandText:=trim(commandText);
  if length(commandText)>0 then
  Begin
    (* Populate our lookup table *)
    mlist:=TStringList.Create;
    try
      mList.Text:=StringReplace(CommandText,';',#13,[rfReplaceAll]);
      for x:=0 to mList.Count-1 do
      begin
        mId:=lowercase(trim(mList.Names[x]));
        FLut.AddOrSetValue(mId, trim(mList.ValueFromIndex[x]) );
      end;
    finally
      mList.Free;
    end;
  end;
end;

Destructor TSourceParameters.Destroy;
begin
  if FLUT<>nil then
    FLut.Free;
  inherited;
end;

function TSourceParameters.Get(Name:String):ISourceParameter;
var
  mData:  String;
begin
  FLut.TryGetValue(name,mData);
  result:=TSourceParameter.Create(mData) as ISourceParameter;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FParams: TSourceParameters;
  mText:  String;
  mFloat: Double;
  mBool:  Boolean;
  mInt:   Integer;
begin
  FParams:=TSourceParameters.Create('name=testing;color=12;number=94.5;gone=true');
  try
    mtext:=FParams.Get('name').AsString;
    mInt:=FParams.Get('color').AsInteger;
    mFloat:=FParams.Get('number').AsFloat;
    mBool:=FParams.Get('gone').AsBool;
  finally
    FParams.Free;
  end;
end;

end.