Archive
And storage for all, Smart solutions to HTML5 files
There is a reason we have sort of left the storage mechanisms for the browser alone. The event-driven nature of JavaScript makes reading and writing of data into a nightmare. Just to store a file you have to respond to 5 (five!) nested events. So forgive me if I havent had time to do something about this until now – but trust me when I say that LocalStorage and SessionStorage which came with the RTL is one of the best solutions you can find.
In short, it goes like this:
- You have to ask to store data into your quota
- You have to then ask to get access to the filesystem
- You have to ask for access to a file-object
- You must request a filereader or writer
- An operation may not execute straight away
Each of these steps happen inside the event handler of the previous.The tricky part here is that these are all nested, which means you can use each element only within *that* event handler. So if you try to access the filesystem object outside the event-handler where you ask for a quota change you will actually get an error; or the JS engine starts to behave oddly. I had to re-boot Chrome because it really crashed when I tried to trick it into behaving linear like we are used to under Delphi and C#.
In Smart it would look something like this:
RequestQuota(Procedure () begin requestFileSystem( procedure () begin requestFileObject( procedure () begin requestWriter( procedure () begin writedata( procedure () begin showmessage("Data written! Yeeej!"); end); end); end); end); end);
In other words — it’s a complete mess. It’s actually twice as bad as above, because you also have to define error handlers besides success handlers. Wish we could get R2/D2’s soon so we dont have to deal with code like this.
File actions
Anyways, since storing files (and reading them) is such a recursive mess, I could probably leave the topic alone and get away with it. But I’m not going to do that. In typical “me” style (which some hate or love, or both) I jump head-first into the mess and get to work, even though this has to be one of the worst tasks I have dealt with in a long time. And that should speak volumes of how absurd the JavaScript file-system is organized.
To make a long story short, the best way to deal with files is through actions. Thats right, the same glorious action system that you find in Delphi and FreePascal. In essence an action is just an object with two common methods: validate() and execute(). The validate function should return the readiness of the object (are all properties set? Can we perform the action now?), while the execute() method implements the actual activity.
I hated this implementation when I first made it, but it was the only system which would secure that your data goes from A to B safely. Initially I wanted a unified storage API where drivers was created after an analysis of the browser environment. So if you were running under phonegap, you would get a driver with full access to the filesystem. If you were running in a normal browser, then you would get a driver which saved data to local storage.
That was a good idea, but sadly the recursive callback loops could not be overcome to provide a linear, blocking storage API like we are used to under Delphi (or any native language for that matter).
The good news
The good news in all of this is that Actions perform very well! I mean, you tend to isolate reading and writing of data in one place, so creating an action object is no different from creating a file-object. And it’s the same with loading. Under HTML5 loading data on a mobile device typically involve a dialog with a spinner or something while you load your data — so triggering this from an action is easier than through 2-3 event handlers.
Secondly, with the streaming system in place you dont have to bend the knee to JavaScript. You write the data as you always have with streams, streamwriters and true binary memory. And when you are done composing your file-format, just execute a pre-defined action for saving and forget about it (how cool is that!).
So how do we store files? Like this:
var mAction: TFileActionSave; begin mAction:=TFileActionSave.Create; mAction.FileName:="document.txt"; mAction.FileMode:=fmPermanent; mAction.FileData:=FStreamToSave; mAction.Execute(NIL);
Pretty neat huh? And if you want to be notified when the file is properly written to disk (or whatever storage medium you select), then you can just assign an event handler, like this:
var mAction: TFileActionSave; begin mAction:=TFileActionSave.Create; mAction.FileName:="document.txt"; mAction.FileMode:=fmPermanent; mAction.FileData:=FStreamToSave; mAction.OnExecute:=procedure (sender:Tobject) begin showmessage("File has been saved!"); TFileActionSave(sender).free; end; mAction.Execute(NIL);
Device separated actions
Actions for performing singular activities are not new, Delphi has had them for ages. And they are really helpful (especially for UI programming). But Delphi’s actions are a bit different from our type of actions here. Our type of actions are expected to be executed once, then disposed or left to be eaten by the garbage collector. You can recycle them naturally but it serves little purpose.
In the event handler above we dispose of the action in the OnExecute() handler, just to make sure no reference to the filesystem lingers in the system. You don’t have to do this, but it’s always best to write things properly. It costs little and can make a huge difference. Some browsers dont take well to having a filesystem object floating around in memory. Chrome goes bananas if more than one reference targets the same object for instance.
Either way, the really cool part is that you can now write your IO code once, and it will run on all supported platforms. If you execute this after phonegap compiling your app, it will store files on your device’s real filesystem. If you execute it in a normal browser (like you are using now) then it will store data in the sandboxed environment (of which you have a maximum of 5 megabytes to play with).
The final result
Well, having cleaned up this mess as best I can, here is the final result. I have made the example below a bit messy on purpose just to show you how simple actions are.
What this routine does is to first generate a small file, execute the “save” action — and when the save routine is done and the file is stored – we create a loading action and read it back again.
It will write out the string to the console. And if you dont believe this is the simple version, feel free to check out system.io.pas when we release this code later. I think you will be very thankful that you have Smart Mobile Studio to deal with all this so you can focus on the fun stuff – writing cool applications!
procedure TForm1.W3Button4Click(Sender: TObject); var mAction: TFileActionSave; begin mAction:=TFileActionSave.Create; mAction.FileName:="document.txt"; mAction.FileMode:=fmTemporary; mAction.OnExecute:=procedure (sender:Tobject) begin var mLoader:=TFileActionLoad.Create; mLoader.FileData:=TMemoryStream.Create; mLoader.FileName:='document.txt'; mLoader.FileMode:=fmTemporary; mLoader.OnExecute:=Procedure (sender:TObject) begin try var mReader:=TReader.Create(mLoader.FileData); writeln(mReader.ReadString); except on e: exception do writeln(e.message); end; end; mLoader.Execute; end; mAction.FileData:=TMemoryStream.Create; var mTemp:=TWriter.Create(mAction.FileData); mTemp.WriteString("This is some data"); mAction.Execute; end;
Well – enjoy!
SQLite + Smart Mobile Studio = True
In case you missed the great moment, here is a link to my previous post on the subject.
In short: Someone has ported the engine SQLite database engine to JavaScript. This means that you can now create, query, save, load and otherwise do whatever you wish without relying on the browser to provide you with a native DB API. This means that if you desire SQL database support in your mobile applications then Smart Mobile Studio now provides that out of the box!
I must mention though that we also provide our own lightweight TW3Dataset class, which for known table structures is much more efficient and faster to work with. But TW3Dataset does not have SQL support and searching for records must be done “the old way”. The SQLite engine applies internal indexes to make searching for data fast and simple, and you get to use SQL which can simplify complex expressions.
Libraries
The SQLite implementation is pure JavaScript and will be stored in the libraries folder. When you include the sqlite unit in your projects, this library is automatically included – and the file copied to your /res/ folder.
To initialize the SQLite driver you simply do like this:
procedure TForm1.InitializeForm; begin inherited; w3Button1.enabled:=False; w3_RequestAnimationFrame( procedure () begin SyncDBStart; end); end; Procedure TForm1.SyncDBStart; begin if CheckDBEngine then begin FDB:=TSQLiteDatabase.Create; w3button1.enabled:=True; end else w3_RequestAnimationFrame(SyncDBStart); end;
As you can see from this code, I disable the GUI while the database engine is loading. I use an async-loop to check if the driver has initialized, and only when true do I re-enable the GUI and create an instance of the database.
You may want to modify your application unit and make sure the driver is loaded before you show a form, or perhaps show a fancy CSS3 dialog with “Loading, please wait” until all your resources are in place? The new system.fileutils.pas unit should give you some inspiration there 😉
Well, here is a picture of the testbed app. Notice the bytesize of a SQLite database with 10.000 inserted records (!)
This means that you can easily stuff thousands of records into a database stored in LocalStorage (max 5 megabytes)! Perfect for lazy updates where you upload the data to your server when the device is connected to the internet.
Enjoy!
Smart Mobile Studio and the SQLite engine (!)

SQLite is now 100% native JS
I am so excited right now I can hardly type straight. This is so awesome that I hardly know where to begin!
Some guy decided to port over the whole SQLite engine from C to JavaScript. That’s right, not an interface to use the DLL, or read the tables or anything like that; a complete and full port of the entire SQLite database engine converted to JavaScript.
This means that you dont need to fiddle with WebSQL or whatever restriction browser vendors have put on reading data. The entire SQLite engine itself is now capable of running inside your Smart Mobile Studio applications.
So you can load, download and even generate binary SQLite database files. If you have a script on your server to accept uploads you can even save those files — or what about creating a SQLite editor so people can design their tables in the browser?
Needless to say I am really happy about this find and jumped straight into it to write a wrapper. I’m not sure we will be able to get this into the next update – but if not, you can download it from this website. It is just to fantastic not to include.
This means you don’t get one DB engine in the next update – but two! system.dataset and system.sqlite all in one go.
Smart Mobile Update, oh man this rocks!
Do you sometimes feel a bit envious of C# programmers with all their cool IDE features? Like automatic updates, built-in package manager which downloads, installs and does all the grunt work for you? I mean, Visual Studio’s nuget package manager looks almost like appstore, but with free packages which can be installed with a click.
I know I have. Being a Delphi/FPC programmer can be tiresome. Especially when it comes to component updates, RTL updates and god knows what else you have to manually deal with.
Well then It’s with great please I assume the role of whistleblower and show you a “peek” of the upcoming Smart Mobile Studio update architecture. That’s right, while you were sleeping we were building a server infrastructure – and one of the features is about to emerge publicly!
Updates for all
Imagine this: Someone at HQ locates a bug in one of the RTL units. Today this means registering a case in fogbugz, providing reproducible code and much, much more. And depending on how critical it is – it can take a while before the ticket comes up to be fixed.
Our new system allows us to do immediate updates. So whenever we add a new feature or fix a bug, it’s fixed straight away — and it is available immediately. All you have to do is click “update” once in a while and you get all the changes, just like Visual Studio and Mono users do!
And we have channels, meaning different branches you can check out, like “Beta” and “Nightly builds” and so on. But please note that these are reserved for paying customers only. The update system takes care of license validation, tracking – updating your executables as well as the VJL + RTL codebase. So this is more or less a perfect solution for serious HTML5/Pascal programmers as you can get. And dont get me started on automatic package installation (ops! Did I say that out loud? Darn…).
I soooooo want to blow the whistle on our other features, but I can’t! Not yet. But the moment they are ready for public ears, rest assured that I’ll play the proverbial bagpipe on all of them 😀
Enjoy!
Microsoft Phone? Yes. And it rocks!
When I tried a Microsoft phone some eight years back it was a less than satisfactory experience. To call it a phone is perhaps to stretch the definition, it was more like a brick of HTC which could be used to make a call -or defend yourself against attacking marauders. No touch screen naturally, since that appeared a year or two later — and the only redeeming quality I can remember was the fact that it could be hooked-up to your PC and programmed quickly. I actually connected it, started visual studio and had a working “hello world” application in less than 10 minutes.
“I am actually tempted to get rid of my iPhone right now”
While my general impression of that old Microsoft phone was terrible, the experience of “connect and code” has stayed with me. And my terrible experience had not so much to do with the OS, which was actually quite excellent at the time — but more with the physical phone itself.
So when I started coding apps for Apple a couple of years back- mentally I compared my experience to that of my first HTC/Microsoft experience. I was quite shocked to find that the Apple development process was so.. how can I put it, complete slavery? I mean having paid in blood to get a new Iphone, which is your property after all, you do expect to be able to put your own software on it right? Well not if Apple has anything to say about it. Seems to me that you don’t really own an Apple product, you lease it for the duration of its life-cycle. And you never get to decide what software you can run, especially not some home-brew code you cooked up yourself; No, you are allowed to pick from a pre-defined menu defined by Apple. A bit like politics where you are expected to select from a pre-defined list of candidates (pick your marionette of preference, but it makes no difference what so ever).
So while Apple may be the leading force in mobile technology today, I still remember Microsoft development as a much easier and pleasant experience. You did not have to digitally sign your own applications just to use them on your own hardware. Nor did you have to pay to create software for what is by definition your own property. And last but not least, creating and deploying in-house software to X number of devices in your organization was your own bussiness. Microsoft did not meddle in how you used your device, nor would that be a natural occuring thought. It’s your phone and what you put on that phone is your choice.
That was before Apple came along however.
Beware slumbering giants
Well with IPhone in hand today I went out and bought a Microsoft Lumia. It was so cheap that I simply could not say no. I need it for testing Smart Mobile Studio JavaScript code first and foremost, but I was also curious to see what a Microsoft phone could do; I mean compared to the gazillion Android offerings and onslaught of Apple quality assurance slogans we have learned to live with. That’s a pretty stiff competition by the way, so Microsoft have more than their work cut out for them.
Between you and me, I have a gut feeling that Microsoft is brewing on something. Have you noticed how Visual Studio suddenly have something called “Universal apps” lately? So you can create an app in C# that runs on Windows, XBox, Windows Embedded (read: tablets and drones) and Microsoft Phones.
This means that it’s going to be hard for developers to say “no” to Microsoft phone development since they get support for that free out of the box.
“Seriously. I had an Android phone for roughly six months and I ended up
giving it away with a 3000 NKR loss because I hated it so much”
So don’t be surprised if you start seeing more Microsoft phones out there — because while Microsoft has been slumbering, we all know that M$ is very, very good at one thing: making monopolies. With their complete abstraction from X86, we are going to see a tidal wave of cheap ARM devices flooding the market in 2-4 years running Windows 10.
What about the phone
Now to the phone! I love it! Seriously. I had an Android phone for roughly six months and I ended up giving it away with a 3000 NKR loss because I hated it so much (Samsung Galaxy S4). So forget Android is all I have to say.
Microsoft mobile is polished, intuitive and has everything you expect from a modern phone “and then sum”. Easy to call, easy to Skype, chat and perform all manners of modern communications. Stuff like E-mail and Facebook check-in is magically done for you once you have entered a couple of credentials, and you stay connected to your Microsoft account from the start. You can also sign up for an XBOX account if you want to download games or just testdrive some “universal apps” (see, told you they would arrive!). So getting the phone up and running was easy, polished and pleasant.
In short: The phone is responsive, has great looking animated menus with a snappy interface. Wow, I cant believe I have ignored Microsoft for so many years, because this phone rocks!
Android never quite made the cut in my book. It’s to much of a mess with to many gaping security holes just waiting to be exploited (and they usually are). Apple is strung to tightly and bound on hands and feet to their money-making model which in the end serves only Apple and not the consumer.
Microsoft is the middle-ground, closer to Apple than to Android, but more polished and friendly than both of them combined. I absolutely have fallen in love with this device.
Oh and the battery life is exceptional! I have gotten used to my iPhone being constantly low on power. The Lumia was fully charged in 18 minutes and is not even at 70% 6 hours later (with constant use).
We need alternatives
The market desperately needs more than two operative systems. It’s a bit like politics. If you only have two parties you dont really have politics, just two factions putting on a show to dazzle the weak-minded masses who gladly relinquish their freedom for bread and circus. Which is exactly what we are seeing between Google Android and Apple iOS. They have some 300 (figuratively speaking) lawsuits against each other on patent infringement at any given point in time, while they throw more and more pointless features onto smaller and smaller footprints. It’s just plain silly how much crap we have gotten used to in such a short time. Remember when a phone was just a phone? Now it’s a fashion statement.
Android suffers from being open-source, with no legal entity taking true responsibility for quality (and forget Google, they like to have their name on it, but shun any responsibility). Although google is trying to up the quality of the Android store – let’s face it, the quality of apps on Android is ridicules compared to iOS. Apple may be security nazis with their application signing and serial key madness, but that at least has paid off with a huge catalog of quality titles.
Microsoft is nowhere near delivering the same number of apps (they have around 97.000 apps, Apple is probably near 500.000 by now). But I love this phone and I am actually tempted to get rid of my iPhone right now, just so I can buy a bigger and faster Microsoft phone. I picked up my Lumia for 780NKR which is peanuts compared to my iPhone 6 (8000 NKR). I can only imagine what type of device I could get from Microsoft at that price.
Well — I strongly urge you to try out the Microsoft phone before you get an Android device. Seriously, why would you want a phone that needs a virus killer? Android is a mess! It’s so-called “open policy” comes at a cost and that cost is the virus infected, scam ridden filth that is Android. A system which has allowed cheap corner-shops in asia to flood the market with fake low-quality devices fooling millions of people on a daily basis.
We need more alternatives, solid alternatives, something which is neither Android nor IOS. And believe it or not but Microsoft has nailed it with the Lumia. It’s one hell of a phone with all the cool stuff you expect from iOS, but with the freedom Android users brag about – but here it’s more mature, in the sense that all adults understand that there is no freedom without laws and boundaries.
Music for the masses
One special feature I want to mention is the free access to music Microsoft gives you. The phone allows you to create your own radio mixes. So you select a few bands you like, and based on that it creates a continuous playlist for you – including bands who fall into the same category. Once in a blue moon you get a few commercials – but this system is much easier to get started with than wimp. And it’s free (you can also sign up for premium services just like wimp).
What amazed me was that within 5 minutes of owning the phone, I was able to listen to a ton of free music. Compare that to Apple’s regime where every single item must be bought! Not to mention the unfair rules of Apple, where they simply ban competing products. Talk about unfair monopoly, Apple is far worse than Microsoft ever was if you ask me.
Also, the music features are built into the phone, And if you love music, you are going to love the easy access you get here.
Another thing is also the ring-tone creator. Again it’s free and comes with the phone. No more having to buy ring-tones, or fooling iTunes to use MP3 encoded files. Just copy over the mp3 you want or record something — cut, copy and paste. Done!
My new favorite
iOS has been my favorite so far due to quality of service and their well stocked app library, not to mention the ability to sync music and videos automatically. Which Android still wont do out of the box. You have to copy over MP3’s manually or buy an app and desktop app to help you. So in terms of technical excellence Android loses due to an operative system which seems to be put together by hob-goblins, lacking even the most rudimentary security. It also loses flat down in friendliness because -there must be a limit to the amount of settings a man has to tweak just to call his bloody girlfriend(!) It’s overkill, pure and simple – to present users with this level of variables. Some of them quite critical as well (affecting battery lifetime).
It’s just a silly trick to sell phones. The more “features” Android can list, the more impressed stupid people are who more often than not dont have a clue what it means. Does your mom benefit from controlling the level 2 Java cache? Ofcourse not! Are these really features? Let’s call a horse for a horse and see it for what it is –a sales pitch.
Well, whatever Apple or Google dazzle you with – Microsoft does it all, and they do it better by leaving out the rubbish and keeping the good stuff. In fact, the latest Microsoft phones are right up there with iOS, but with one massive advantage: It’s not bolted shut by nazis who insist of milking you for every single penny they can get. You are free to program apps running on your own phone, and you can even copy it over to other phones without asking for permission from the silicon papacy at Apple HQ to do so.
The moment you want to push your software out to the store you naturally have to go through a signing process, that’s to be expected. But the quality and ease is 100 times better than anything Apple is offering – so Microsoft wins on all accounts.
So I am happy to report that I have found my new favorite mobile device — and the source could not be more unexpected! It’s the Microsoft Lumia! So tomorrow im updating my Cell subscription and I’m going for the shiny new Lumia 930 — selling my IPhone in the process.
Good bye Apple, and thanks for all the fish!
Guess it’s time to whip out Smart Mobile Studio and Visual Studio and compile my first HTML5 App 🙂
Delegates, a fun look at multi-casting with Smart Pascal
This is just for fun, but here is the smallest possible delegate (read: multi-cast events) I could come up with. The lack of generics makes this tricky (its even tricky with generics), so this is probably as close as we get.
It should be easy enough to add operator overloading in the += and -= style made popular by Smart Pascal and C#, that way you could do stuff like:
// Install a new delegate handler FHandle:=FDelegateOnClick += Procedure (sender:TObject;e:TDelegateParams) begin end; // Uninstall handler FDelegateOnClick -= FHandle;
Well, here is the code. Small and compact as always:
type TDelegateNameValuePair = Record nvName: String; nvValue: Variant; end; TDelegatePairList = array of TDelegateNameValuePair; TDelegateParams = class(TObject) private FData: TDelegatePairList; public property Data:TDelegatePairList read FData write FData; function Set(const ValueName:String; const Data:Variant):TDelegateNameValuePair; function Get(const ValueName:String):Variant; end; TDelegateParamsClass = Class of TDelegateParams; TDelegateProcedure = procedure (sender:TObject;e:TDelegateParams); TDelegateEntryList = Array of TDelegateProcedure; TCustomDelegate = Class private FEntries: TDelegateEntryList; public function CreateParams:TDelegateParams;virtual; function Add(const Entrypoint:TDelegateProcedure):THandle; procedure Remove(Const Handle:THandle); procedure Invoke(const Params:Array of Variant);overload;virtual; procedure Invoke(const sender:TObject;const Params:TDelegateParams);overload; end; //########################################################################### // TDelegateParams //########################################################################### function TDelegateParams.Get(const ValueName:String):Variant; var x: integer; begin result:=null; for x:=0 to FData.Count-1 do begin if sametext(ValueName,FData[x].nvName) then begin result:=FData[x].nvValue; break; end; end; end; function TDelegateParams.Set(const ValueName:String; const Data:Variant):TDelegateNameValuePair; begin result.nvName:=ValueName; result.nvValue:=Data; FData.add(result); end; //########################################################################### // TCustomDelegate //########################################################################### function TCustomDelegate.CreateParams:TDelegateParams; begin result:=TDelegateParams.Create; end; procedure TCustomDelegate.Remove(Const Handle:THandle); var x: Integer; src: THandle; begin for x:=0 to FEntries.count-1 do begin asm @src = (@self).FEntries[@x]; end; if Src = Handle then begin FEntries.Delete(x,1); break; end; end; end; function TCustomDelegate.Add(const Entrypoint:TDelegateProcedure):THandle; begin asm ((@self).FEntries).push(@Entrypoint); end; asm @result = @Entrypoint; end; end; procedure TCustomDelegate.Invoke(const sender:TObject; const Params:TDelegateParams); var x: integer; begin for x:=0 to FEntries.count-1 do begin try FEntries[x](sender,Params); except on e: exception do; end; end; end; procedure TCustomDelegate.Invoke(const Params:Array of Variant); var x,y: integer; mParams:TDelegateParams; begin for y:=0 to FEntries.count-1 do begin mParams:=createParams; for x:=0 to Params.count-1 do mParams.set("value" + x.toString,params[x]); try FEntries[y](self,mParams); except on e: exception do; end; end; end;
Using the delegate
Since I did not include operator overloading, we resort to anonymous procedures to register our handler. Please note that TCustomDelegate.Add() return a reference-handle which you can use to un-install the handler procedure later (!)
Here is how you can go about it. Also notice that Invoke() is overloaded, so you can invoke the delegate passing the parameters as an array of variant.
var mDelegate: TCustomDelegate; begin mDelegate:=TCustomDelegate.Create; mDelegate.Add( Procedure (sender:TObject;e:TDelegateParams) begin showmessage(e.data[0].nvValue); end ); mDelegate.Invoke([Variant("this is a test")]);
Remember to derive your own delegate objects, and also to override the CreateParams method to return your own parameter instances.
So in short: Inherit from the customdelegate with your own class. Override and derive your own TDelegateParams. You may also want to get rid of the read/write stuff since that is quite slow. Change that with your own parameters for the delegate.
This is actually how we create events and delegates in C# — so it’s hard work 🙂
The Smart Mobile Studio Competition!
I want to remind every one about the Smart Mobile Studio competition I launched earlier.
It’s still early (I have received two really good entries already), so if you own Smart Mobile Studio – or even if you don’t (heck you can download the trial version and have a go) and fancy winning the latest Raspberry PI 2 (model B, the new one that runs Windows 10) then this is your chance!
You can find the details regarding the compo here. The rules are straight forward and easy, and remember: this is not a graphical demonstration competition. This competition is about making the best component! And writing components is very entertaining, especially for a programming environment as young as Smart Mobile Studio. It lacks many of the controls which we take for granted under Lazarus or Delphi (hint).
It’s ready to be sent to your place
We are practically giving this Raspberry PI away; It’s just lying there in its box ready to be shipped to wherever you live; dying to be turned into something fun and useful. And even if you don’t need it, your kids will love playing every nintendo, amiga, sega and arcade game ever created (just install PIMame and turn it into an arcade machine).
So what are you waiting for? Impress us with a new toolbar, a new button-bank, sinus scrolltext or whatever control type you love to code! A hex editor would be nice (or any editor to be honest, I havent gotten around to coding one yet).
System.Interop “how to” for Smart Mobile Studio
Smart Mobile Studio and the dialect “Smart Pascal” has roots in the Object Pascal community. The compiler and toolkit is written purely using FreePascal and Delphi, and naturally the run-time library for Smart Pascal is heavily influenced by both.
Background
What is less known is that Smart Mobile Studio in general, both the IDE and the RTL architecture, is equally inspired by the Mono project. The entire layout of the IDE is almost identical to Mono-Develop as it existed 4 years ago, while the RTL and application framework borrows from MonoTouch by exposing central constructs (like TApplication) purely through partial classes. These are language features which does not exist in FreeePascal or Embarcadero Delphi.
The unit Interop.pas which is a part of the system namespace (system.interop) is inspired by the mono .NET equivalent. Under Mono the various memory and type transformation classes are spread out over many different locations. Under Smart Mobile Studio we have decided to collect and implement these .NET features in a single unit. Namely system.interop (short for: System interoperability).

The Smart RTL is seriously fast
Memory management under HTML5
JavaScript does not expose any form of memory management. The closest thing to allocating memory under JavaScript is through JArrayBuffer and JTypedArray. JArrayBuffer is an un-typed memory segment without read or write access. The buffer can only be accessed by creating a descendant of JTypedArray and connecting that to JArrayBuffer. As such:
/* Allocate memory buffer, 1024 bytes */ var memBuffer = new ArrayBuffer(1024); /* Allocate R/W access through a typed array */ var memAccess = new UInt8Array( memBuffer );
Needless to say, working with memory like this quickly becomes tiredsome, error prone and messy. Especially when coming from a FreePascal or Delphi background, where a simple call to AllocMem() is enough to reserve memory on the heap.
Memory Management under Smart Mobile Studio
The Interop unit introduces 3 different means of working directly with memory, there are:
- Streams
- Memory Buffers
- Marshaled classical memory access
Marshaled memory access
Due to the shortcomings of JavaScript the only way to expose and work directly with memory is through a technique called marshaling. It essentially means that you are abstracted from pure machine localized addresses (pointer types) and instead operate with reference objects (location objects).
Such a reference object contains two pieces of information:
- A reference (handle) to the associated JArrayBuffer
- An entrypoint (offset) into the arraybuffer
For instance, under classical object pascal the following code is quite common:
// pointer type containing the address var mBuffer: PByte; // Allocate memory mBuffer:=AllocMem(1024); try // Work with memory here finally // Release memory freemem(mBuffer); end;
Using marshaled objects Smart Mobile Studio is capable of delivering the exact same:
// pointer type containing the address var mBuffer: TAddress; // Allocate memory mBuffer:=TMarshal.allocMem(1024); try //work with memory here finally // Release memory TMarshal.freemem(mBuffer); end;
Marshaled references also have the benefit of helper functions. So advancing further into an allocated segment is done via the TAddress.Addr() function.
// pointer type containing the address var mBuffer: TAddress; // Allocate memory mBuffer:=TMarshal.allocMem(1024); try mBuffer:=mBuffer.Addr(2); //Advance reference by 2 bytes finally // Release memory TMarshal.freemem(mBuffer); end;
Since JavaScript is garbage collected we can also approach memory offsets quick and dirty, like below; Fact is we really dont need to call FreeMem() because the garbage collector will come around and clean up after us later. But sloppy code has a proven negative impact on performance (memory fragmentation leads to sudden cpu spikes as the GC get’s busy), so I strongly advice you to stick with best practices object pascal.
var mBuffer: TAddress := TMarshal.allocMem(1024).addr(2);
Access to memory with such elegance is unheard of in the world of JavaScript. Marshaled reference objects can be found in many languages, but we are the first to introduce this for JavaScript. The speed benefit is likewise phenomenal compared to other solutions. In fact, our initial read/write tests outperformed all versions of native Embarcadero Delphi prior to Delphi XE.
Memory buffers
While marshaled references and memory allocations are essential for legacy compatability, porting code from freepascal or Delphi to HTML5 – being able to directly interact with a memory segment is vital for any modern platform.
As such, the Interop unit provides the TMemory class. Using the methods of this class you can allocate, release, move, copy, export, read and write directly to memory. The class implements caching for maximal speed enhancement. All intrinsic JavaScript datatypes are supported (Int16, Int32, Float32, Float64, String, Boolean).
Special attention should be made to the class-procedure Move() and Fill() which are equal to the classical FreePascal and Delphi variations. Unlike their classical counterparts these methods accepts TMemoryHandle rather than Pointer or marshaled TAddress objects.
Using Move with Marshaled Addresses
The TAddress class exposes a property named “Segment” of type TMemoryHandle. This can be used with Move() and Fill() as demonstrated below:
var src: TAddress; dst: TAddress; TMemory.Move( src.segment, // source memory src.entrypoint, // source offset dst.segment, // target memory dst.Entrypoint, // target offset 500 //bytes to move ); TMemory.Fill( src.segment, src.entryPoint, 500, TDatatype.CharToByte("Z") );
It must be noted that the above code is just for explanation. Both Move() and FillChar() are implemented in the TMarshal class. The above demonstration is just to provide reference material on their use and how marshaled memory works.
Converting data
JavaScript is essentially type-less. The concept of “typed-arrays” was implemented a while back because they represent a significant speed boost. No matter if you are working on complex calculations or want to manipulate pixels on byte level, being able to work directly with memory is essential for inter-operability with other languages and file-formats.
Converting intrinsic (built in types) to binary can be very hard under JavaScript. As of writing, Smart Mobile Studio provides the most accurate and fastest means of doing this.
The class TDatatype provides methods for converting intrinsic datatypes to “array of bytes” and also from TByteArray back into intrinsic values. The class itself uses speed optimalization by pre-allocating conversion space when the unit is loaded into memory. This makes data conversion extremely fast, much faster than any other JavaScript solution out there.
Using TDatatype is very easy:
var x: Integer; mData: TByteArray; // convert int32 value $1200 into 4 bytes mData := TDatatype.Int32ToBytes($1200); // write bytes to the console for x:=0 to mData.length-1 do writeln(mData[x]); // Alter first byte just for fun mData[0]:=$FF; // Write modified integer value to the console Writeln( TDataType.BytesToInt32(mData) );
The following methods are provided by TDatatype for conversion of datatypes:
TDatatype = Class public class property Bits:TBitAccess; class function Int16ToBytes(Value:Integer):TByteArray; class function Int32ToBytes(Value:Integer):TByteArray; class function Float64ToBytes(Value:Float64):TByteArray; class function Float32ToBytes(Value:Float32):TByteArray; class function StringToBytes(Value:String):TByteArray; class function BooleanToBytes(Value:Boolean):TByteArray; class function BytesToInt16(const Data:TByteArray):Integer; class function BytesToInt32(const Data:TByteArray):Integer; class function BytesToFloat32(Const Data:TByteArray):Float; class function BytesToFloat64(Const Data:TByteArray):Float; class function BytesToString(const Data:TByteArray):String; class function BytesToBoolean(const data:TByteArray):Boolean; class function StrToBase64(Value:String):String; class function Base64ToStr(Value:String):String; class function ByteToChar(Const Value:Byte):String; class function CharToByte(const Value:String):Byte; class function StrToTypedArray(value:String):TJSByteClass; class function TypedArrayToStr(const value:TJSByteClass):String; end;
Working with bits
The TDatatype class exposes a class-property named TBitAccess, which contains only class methods for manipulating bits. As of writing the following methods exists:
TBitAccess = Class public class function Get(Const index:Integer;Const Value:Byte):Boolean; class function &Set(Const Index:Integer;Const Value:Byte; const Data:Boolean):Byte; class function Count(Const Value:Byte):Integer; class function ToByteString(const Value:Byte):String; class function FromByteString(const Value:String):Byte; class function Dismantle(const Value:Byte):TByteArray; class function Assemble(const Value:TByteArray):Byte; end;
Note: TMemory also exposes getBit and setBit methods for the whole allocated memory. This allows you to use a whole segment as a bit-buffer. This is often used by compression, sound generators and classes which communicates with hardware (see Smart Support for hardware platforms).
Working with Streams
While marshaled memory allocations and TMemory represents fast and direct access to raw data, RTL software typically base themselves on streams. In essence Streams and buffers represent the same thing, except that a stream maintains a cursor which is automatically updated as you advance through the content.
Smart Pascal implements the base-class “TStream” which is a purely abstract stream class, just like it exists under C#, FreePascal and Delphi. Deriving from this is TMemoryStream and TStringStream. We will no doubt add more streams to the mix at a later date, but due to the nature of HTML5 and the restrictions on JavaScript, file-streams serve little purpose at this point in time.
Using streams is done much like under FreePascal and Delphi:
var mStream: TMemoryStream; mStream:=TMemoryStream.Create; try // use stream here finally mStream.free; end;
Reading and writing to streams can either be done directly using TStream.Write() or TStream.Read(), both these methods accepts an array of byte (TByteArray). This makes streams slower to use than TMemory or TMarshal operations.
var mStream: TMemoryStream; mWriter: TStreamWriter; mStream:=TMemoryStream.Create; try mWriter:=mStream.createWriter; mWriter.WriteInt32($1200); mWriter.WriteString("This is how you write to a stream!"); mWriter.WriteFloat64(139.68504); finally mStream.free; end;
Reading is done via TStreamReader, which you can either create manually or obtain via the TStream.CreateReader() method.
Speed comparison
JavaScript is seriously fast. Much faster than you would imagine, all things considering.
In the first test, which writes 100.000 records into a pre-allocated TMemory instance, we get the following results:
mMake.Allocate(2100021); mStart:=Now; mChunk:=0; for x:=0 to 100000 do begin mMake.Write(mChunk + 0,$AAAA0000); mMake.WriteFloat32(mChunk + 4,19.24); mMake.WriteFloat64(mChunk + 8,24.18); mMake.Write(mChunk + 16,false); mMake.write(mChunk + 17,$0000AAAA); inc(mChunk, 21); end; mStop:=Now;
Time to completion: 0 seconds, 46 milliseconds
In the second test we omit pre-allocation, which will force TMemory to grow and re-allocate it’s cache quite often, depending on the size of the cache (4096 bytes in this case):
Time to completion: 0 seconds, 445 milliseconds
In the third test we do the exact same, but this time using streams and streamwriter. To fully understand what is happening here, for each write, consider the following:
- StreamWriter calls TDatatype to convert the intrinsic value into a TByteArray
- StreamWriter calls TStream to write the data
- TStream maintains a TMemory class, and calls the rather slow Write() operation
- TStream’s TMemory instance has no pre-allocation, and as such re-allocation will occur often
Time to completion: 0 seconds, 519 milliseconds
These numbers are almost ridicules. I thought something was wrong somewhere at first, and had to check that data was actually written and that it had written the data properly. But yes, the above numbers are correct and memory access under JavaScript when done right is beyond anything I have seen elsewhere.
As of writing my code is roughly two times faster than Perl and Python, it’s also faster than any native Embarcadero Delphi version except Delphi XE7. Only FreePascal and C# Mono compiled to machine-code using LLVM optimization is capable of performance like this. Which is to some degree embarrassing and humiliating for Delphi, a product costing 100 times more than Smart Mobile Studio.
On the positive side, it spells a bright future for Smart Mobile Studio, especially when interacting with nodeJS and hardware, which require powerful and fast code.
The Zen of Smart Pascal
Something so elegant with memory management in place under Smart Mobile Studio. Moving pixels used to be so mind-numbingly slow compared to pointers. Now it’s a one-liner and faster than Embarcadero Delphi (only FreePascal is keeping pace).
The method ToBuffer() used to be over 200 lines long, as was LoadFromBuffer(). With the advent of TMemory, TMarshal and various low-level kick-ass to-the-bone methods now in place, such are things of the past. Now Smart Mobile Studio coders can enjoy the full power of modern OOP development under HTML5 using all the tools they are used to from FreePascal and Delphi.
function TW3Image.ToBuffer:TMemory; begin if Ready then result:=TMemory.Create(toImageData.Handle.data); end; procedure TW3Image.LoadFromBuffer(const Memory:TMemory); var mContext: TW3GraphicContext; mCanvas: TW3Canvas; mData: JImageData; begin if Ready then begin mContext := TW3GraphicContext.Create(Null); try mContext.Allocate(PixelWidth,PixelHeight); mCanvas := TW3Canvas.Create(mContext); try (* Get pixel buffer *) mData:=mCanvas.Handle.getImageData(0,0,PixelWidth,PixelHeight); (* over-write pixel buffer with our data *) TMemory.Move(memory.Handle,0,Variant(mData.data),0,mData.data.length); (* put pixel buffer back *) mCanvas.Handle.putImageData(mData,0,0); (* And force a re-load via Base64 *) LoadFromUrl(mCanvas.ToDataURL("png")); finally mCanvas.Free; end; finally mContext.Free; end; end else Raise Exception.Create ('Loading image from memory failed, surface must be allocated first'); end;
Smart Mobile Studio and low level memory access!
For the past 7 .. 8 days I have spent most of my spare time working on two particular units: system.interop and smartcl.legacy. I don’t think I have ever spent so much time on a unit (at least not under SMS) for many years. Not because it’s super hard to code these, but because in order to arrive at the best solution – you often have to evolve your ideas through different approaches. You can read my previous post about this here.
But the journey has been worth it. Let me explain why
Memory allocations? But JavaScript doesn’t do that!
System.Interop, which takes its name from the .net framework, is all about code that facilitates interoperability; meaning classes and functions which helps you talk to other systems. Since “other systems” in many cases means native code, being able to work with untyped-memory (which JavaScript does support) and typed-array abstractions (called views, which conceptually functions like pointers) is essential.
I was able to port over both CRC and RLE compression
directly from my Delphi codebase without much change
I am happy to inform you that Smart Mobile Studio now supports a TMemory class, which encapsulates a fully untyped piece of memory. It extends ordinary and boring untyped-memory buffers with the ability to grow, shrink, scale and much more. All in all TMemory has around 50 methods for manipulating memory, so you are well catered for in that department.
So if you are half expecting some sloppy string buffer or something like that, you should be pleasantly surprised.
There is also a class called TDatatype which provides methods for converting intrinsic (built-in) datatypes to bytes, and bytes back to an intrinsic datatype. So you have handy single shot functions like Int32ToBytes, Float32ToBytes and naturally their counterparts (BytesToInt32, BytesToFloat32).
On top of this system we finally reach the pretty high level interface, namely streams. I write “finally” because this has been quite a chore. The central problem is not the browser, nor is it me. The central problem is that the wide majority of JavaScript developers blogging about their code doesn’t have a clue what they are talking about. A whole generation of programmers who never learnt about pointers at school or university (!) An intellectual emergency of epic proportions.
you can now use AllocMem() and the other classical memory management
functions just like you would under Freepascal and Delphi
Now dont get me wrong, I have seen some fantastic code out there and JavaScript is really the language which is seeing more growth than any of the others combined, but if you want to work with untyped memory and accessing them through “views” (read: typed pointers) then you preferably should have some experience with pointers first.
With my 20+ year background in programming I had no problems navigating the docs (once I found them), and although it took me a few days to sift through all the rubbish, separating the good bad, I feel we have truly power-house of a solution on our hands.
Speed
If you think JS is to slow for anything serious, think again! People were shocked when Delphi was humiliated by JavaScript graphics back in 2012. It turns out JavaScript is just faster than compiled Delphi (in this case Delphi 7 .. Delphi 2006). This was a wake-up call for many developers I think.
for x:=0 to 40000 do begin mWriter.WriteInteger($AAAA0000); mWriter.WriteFloat64(19.24); mWriter.WriteFloat64(24.19); mWriter.WriteBoolean(false); mWriter.WriteInteger($0000AAAA); end; RECORDS = 40.000 BYTES = 29 bytes * RECORDS = 1,160.225 Megabytes CACHE = 4096 bytes ======================= DURATION = 2.63 seconds
NOTE: The example above writes through a 4-layer architecture: StreamWriter to stream-object, stream-object to buffer via TDatatype (datatype conversion to bytes), buffer writes to memory. This is one of the more time consuming tests, since the dynamic nature of a stream forces the buffer to re-allocate and move the content frequently.
If we go below the stream architecture, straight to the TMemory class, well moving data around inside is blistering fast (the example above moves data through 4 different objects, which is the price to pay for a good framework). The reason low-level memory operations are fast is because un-typed buffers are allocated “as is” in memory; As a single block with a related pointer defined for the data. So forget everything you know about ordinary arrays under JavaScript;
PS: True pointers under JavaScript are called Typed-Arrays, and serve as a view or window into the allocated memory according to it’s type. So if you use an Int32 type you will naturally be able to access the memory as an array of integers. If you chose a byte pointer (UInt8Array) and connect that to the buffer – you can manipulate the buffer on byte level.
The hard part is creating an infrastructure around these methods, a bridge between intrinsic types and typed/un-typed memory. Which is exactly what System.Interop gives you.
Allocmem? No way!
My SmartCL.Legacy unit is all about helping you move your Delphi or FreePascal code and skill-set to Smart Pascal and HTML5. Since one of the major differences between FPC/Delphi and HTML5 is how graphics are drawn (the HTML5 canvas object bears little resemblence to good old TCanvas) I decided to create a full clone of our old belowed TCanvas. So if you have a ton of working Object Pascal code for drawing graphics around the place, you should now be able to re-cycle it under HTML5 with little or no change.
The same goes for TBitmap, a class that I must admit I have missed myself from time to time. It’s easy to create a graphics context and a TW3Canvas, but old habits die hard and TBitmap still has it’s uses. Even though we have been complaining about it’s limitations for decades 🙂
But what about classical pascal concepts like AllocMem(), FreeMem(), Move() and FillChar() I hear you say?
Well you may think I am joking but I implemented that as well! The hairs on your neck should stand up right about now. Yes you read right, you can now use AllocMem() and the other classical memory management functions just like you would under Freepascal and Delphi.
Dealing with pointers
If you know your JavaScript you may be thinking “But what pointers? JavaScript doesn’t have pointers!”. That is very true indeed. JavaScript doesnt have a type called pointer. So in order to provide such a type, we have to adopt some inspiration from C#: meaning that a pointer under Smart Mobile Studio is actually an object. This technique is called “marshaling”.
Here is how you allocate memory and play around with it:
procedure TForm1.testMemory; var mData: TAddress; begin mData:=TMarshal.Allocmem(1024); try //fill the buffer with zero TMarshal.FillChar(mData,1024,#0); //Fill 200 bytes, starting at offset 100, with the letter "A"; TMarshal.FillChar(mData.Addr(100),200,"A"); //move 200 bytes, starting at offset 200, to position 400 TMarshal.Move(mData.Addr(200),mData.Addr(400),200); finally freemem(mData); end; end;
Pretty cool right? And yes, AllocMem() really does allocate untyped memory. TAddress is just a very, very thin piece of code which serves as a “reference point” into the allocated untyped memory.
The result? Well, I was able to port over both CRC and RLE compression directly from my Delphi codebase without much change.
Marshaling
like mentioned, keeping references to memory through handles and offsets is called marshaling. It’s more or less the same technique as used by CLR under .NET, and before that Java and Visual Basic (and many more languages as well). So these languages have gotten around their initial lack of memory access without to much penalty. I mean – games like MineCraft is written in 100% Java and runs just as fast as native C++ despite the lack of pointers. As does the .NET framework (note: the “lack” of pointers is not really true for the .NET framework, but pointer operations are regarded as “unsafe”).
Marshaling simply means that TAddress contains a reference to the un-typed memory, and also an offset into this memory buffer (see TAddress.Entrypoint property). The “real” memory is only accessed through the operations which act on the memory, and only then through typed-views which ensure safety (sigh).
Let’s take a peek under the hood of TAddress
TAddress = Class private FOffset: Integer; FBuffer: THandle; protected function _getSegRef:THandle;virtual; public Property &Type:JUInt8ClampedArray read ( new JUInt8ClampedArray(JTypedArray(_getSegRef)) ); Property Entrypoint:Integer read FOffset; Property Segment:THandle read FBuffer; function Addr(const Index:Integer):TAddress; function Reflect:TMemory; Constructor Create(const aSegment:THandle; const aEntrypoint:Integer);virtual; Destructor Destroy;Override; end; //############################################################################ // TAddress //############################################################################ Constructor TAddress.Create(const aSegment:THandle; const aEntrypoint:Integer); begin inherited Create; if (aSegment) then FBuffer:=aSegment else Raise EAddress.Create('Failed to derive address, invalid segment error'); if aEntryPoint>=0 then FOffset:=aEntryPoint else Raise EAddress.Create('Failed to derive address, invalid entrypoint error'); end; Destructor TAddress.Destroy; begin FBuffer:=NIL; FOffset:=0; inherited; end; function TAddress._getSegRef:THandle; begin result:=JTypedArray(FBuffer).buffer; end; function TAddress.Addr(const Index:Integer):TAddress; var mTarget: Integer; begin if Index>=0 then Begin mTarget:=FOffset + Index; if (mTarget>=0) and (mTarget < JUint8ClampedArray(FBuffer).byteLength) then result:=TAddress.Create(FBuffer,mTarget) else raise EAddress.Create ('Failed to derive address, entrypoint exceeds segment bounds error'); end else Raise EAddress.Create ('Failed to derive address, invalid entrypoint error'); end; function TAddress.Reflect:TMemory; begin if (FBuffer) then result:=TMemory.Create(FBuffer.buffer) else Raise EAddress.Create('Failed to reflect memory, null reference error'); end;
As you can see from the code above, TAddress is extremely efficient and thin. It only manages the entrypoint into the associated memory-segment, the rest is very simple but effective maintenance code.
Let’s take a closer look under the hood of TMarshal while we are at it:
//############################################################################ // TMarshal //############################################################################ class procedure TMarshal.FillChar(const Target:TAddress; const Size:Integer; const Value:Byte); var mSegment: JUint8ClampedArray; mIndex: Integer; Begin if Target<>NIl then begin mSegment:=JUint8ClampedArray( Target.Segment ); if mSegment<>NIL then Begin mIndex:=Target.Entrypoint; TMemory.Fill(Target.Segment,mIndex,Size,Value); end; end; end; class Procedure TMarshal.FillChar(const Target:TAddress; const Size:Integer; const Value:String); var mSegment: JUint8ClampedArray; mByte: Byte; Begin if Target<>NIl then begin if Value.length>0 then begin mByte:=TDataType.CharToByte(Value); mSegment:=JUint8ClampedArray( Target.Segment ); if mSegment<>NIL then TMemory.Fill(Target.Segment,Target.Entrypoint,Size, mByte); end; end; end; class procedure TMarshal.Move(const Source:TAddress; const Target:TAddress;const Size:Integer); Begin if Source<>NIL then Begin if Target<>NIl then begin if Size>0 then TMemory.Move(Source.segment,Source.Entrypoint, target.segment,target.entrypoint,Size); end; end; end; class procedure TMarshal.ReAllocmem(var Segment:TAddress; const Size:Integer); var mTemp: TAddress; mSize: Integer; begin if segment<>NIL then begin mSize:=JUint8ClampedArray(segment.Segment).length; mTemp:=AllocMem(Size); case (Size>mSize) of true: move(segment,mtemp,mSize); false: move(segment,mTemp,Size); end; //Ensure reference is picked up by garbage collector SegMent.free; Segment:=NIL; Segment:=mTemp; end else SegMent:=AllocMem(Size); end; class function TMarshal.AllocMem(Const Size:Integer):TAddress; var mBuffer: JArrayBuffer; mArray: JUint8ClampedArray; begin result:=NIL; if Size>0 then Begin mBuffer:=new JArrayBuffer(Size); asm @mArray = new Uint8ClampedArray(@mBuffer); end; result:=TAddress.Create(mArray,0); end; end; class procedure TMarshal.FreeMem(Const Segment:TAddress); begin if Segment<>NIL then Segment.free; end;
You could be excused to think that this can hardly provide such advanced features, and you are right. The infrastructure which does the actual moving of data or population of data is inside the TMemory class. Which is far to big to post here.
Well, I hope I have wetted your appetite for cutting edge HTML5 development with Smart Mobile Studio!
Enjoy!
You must be logged in to post a comment.