Home > C#, Delphi, JavaScript, Language research, Object Pascal, Remobjects > RemObjects VCL, mind blown!

RemObjects VCL, mind blown!

For a guy that spends most of his time online, and can talk for hours about the most nerdy topics known to mankind – being gobsmacked and silenced is a rare event. But this morning that was exactly what happened.

Now, Marc Hoffman has blogged regularly over the years regarding the evolution of the RemObjects toolchain; explaining how they decoupled the parts that make up a programming language, such as syntax, rtl and target, but I must admit haven’t really digested the full implications of that work.

Like most developers I have kept my eyes on the parts relevant for me, like the Remoting SDK, Data Abstract and Javascript support. Before I worked at Embarcadero I pretty much spent 10 years contracting -and building Smart Mobile Studio on the side together with the team at The Smart Company Inc.

xo

Smart Pascal gained support for RemObjects SDK servers quite early

Since both the Remoting SDK and Data Abstract were part of our toolbox as Delphi developers, those were naturally more immediate than anything else. We also added support for RemObjects Remoting SDK inside Smart Mobile Studio, so that people could call existing services from their Javascript applications.

Oxygene then

Like most Delphi developers I remember testing Oxygene Pascal when I bought Delphi 2005. Back then Oxygene was licensed by Borland under the “Prism” name and represented their take on dot net support. I was very excited when it came out, but since my knowledge of the dot net framework was nil, I was 100% relient on the documentation.

In many ways Oxygene was a victim of Rad Studio’s abhorrent help-file system. Documentation for Rad Studio (especially Delphi) up to that point had been exemplary since Delphi 4; but by the time Rad Studio 2005 came out, the bloat had reached epic levels. Even for me as a die-hard Delphi fanatic, Delphi 2005 and 2006 was a tragic experience.

image

Removing Oxygene was a monumental mistake

I mean, when it takes 15 minutes (literally) just to open the docs, then learning a whole new programming paradigm under those conditions was quite frankly impossible. Like most Delphi developers I was used to Delphi 7 style documentation, where the docs were not just reference material – but actually teaches you the language itself.

In the end Oxygene remained very interesting, but with a full time job, deadlines and kids to take care of, I stuck to what I knew – namely the VCL.

Oxygene today

Just like Delphi has evolved and improved radically since 2005, Oxygene has likewise evolved above and beyond its initial form. Truth be told, we copied a lot of material from Oxygene when we made Smart Pascal, so I feel strangely at home with Oxygene even after a couple of days. The documentation for Oxygene Pascal (and Elements as a whole) is very good: https://docs.elementscompiler.com/Oxygene/

But Oxygene Pascal, while the obvious “first stop” for Delphi developers looking to expand their market impact, is more than “just a language”. It’s a language that is a part of a growing family of languages that RemObjects support and evolve.

As of writing RemObjects offers the following languages. So even if you don’t have a background in Delphi, or perhaps migrated from Delphi to C# years ago – RemObjects will have solutions and benefits to offer:

  • Oxygene (object pascal)
  • C#
  • Swift
  • Java
water

Water is a sexy, slim new IDE for RemObjects languages on Windows. For the OS X version you want to download Fire.

And here is the cool thing: when you hear “Java” you automatically expect that you are bound hands and feet to the Java runtime-libraries right? Same also with C#, you expect C# to be purely limited to the dot-net framework. And if you like me dabbed in Oxygene back in 2005-2006, you probably think Oxygene is purely a dot-net adapted version of Object Pascal right? But RemObjects have turned that on it’s head!

Remember the decoupling I mentioned at the beginning of this post? What that means in practical terms is that they have separated each language into three distinct parts:

  1. The syntax
  2. The RTL
  3. The target

What this means, is that you can pick your own combinations!

Let’s say you are coming from Delphi. You have 20 years of Object Pascal experience under your belt, and while you dont mind learning new things – Object Pascal is where you will be most productive.

Well in that case picking Oxygene Pascal covers the syntax part. But you don’t have to use the dot-net framework if you don’t want to. You can mix and match these 3 parts as you see fit! Let’s look at some combinations you could pick:

  • Oxygene Pascal -> dot net framework -> CIL
  • Oxygene Pascal -> “VCL” -> CIL
  • Oxygene Pascal -> “VCL” -> WinAPI
  • Oxygene Pascal -> “VCL” -> WebAssembly

(*) The “VCL” here is a compatibility RTL closely modeled on the Freepascal LCL and Delphi VCL. This is written from scratch and contains no proprietary code. It is purely to get people productive faster.

The whole point of this tripartite decoupling is to allow developers to maximize the value of their existing skill-set. If you know Object Pascal then that is a natural starting point for you. If you know the VCL then obviously the VCL compatibility RTL is going to help you become productive much faster than calling WinAPI on C level. But you can, if you like, go all native. And you can likewise ignore native and opt for WebAssembly.

Sound cool? Indeed it is! But it gets better, let’s look at some of the targets:

  • Microsoft Windows
  • Apple OS X
  • Apple iOS
  • Apple WatchOS
  • Android
  • Android wearables
  • Linux x86 / 64
  • Linux ARM
  • tvOS
  • WebAssembly
  • * dot-net
  • * Java

In short: Pick the language you want, pick the RTL or framework you want, pick the target you want — and start coding!

(*) dot-net and Java are not just frameworks, they are also targets since they are Virtual Machines. WebAssembly also fall under the VM category, although the virtual machine there is bolted into Chrome and Firefox (also node.js).

Some example code

Webassembly is something that interest me more than native these days. Sure I love the speed that native has to offer, but since Javascript has become “the defacto universal platform”, and since most of my work privately is done in Javascript – it seems like the obvious place to start.

Webassembly is a bit like Javascript was 10 years ago. I remember it was a bit of a shock coming from Delphi. We had just created Smart Mobile Studio, and suddenly we realized that the classes and object the browser had to offer were close to barren. We were used to the VCL after all. So my work there was basically to implement something with enough similarity to the VCL to be familiar to to Delphi developer, without wandering too far away from established JS standards.

Webassembly is roughly in the same ballpark. Webassembly is just a runtime engine. It doesn’t give you all those nice and helpful classes out of the box. You are expected to either write that yourself – or (as luck would have it) rely on what language vendors provide.

RemObjects have a lot to offer here, because their “Delphi VCL” compatibility RTL compiles just fine for Webassembly. There is no form designer though, but I haven’t used a form designer in years. I prefer to do everything in code because that’s ultimately what works when your codebase grows large enough anyways. Even my Delphi projects are done mainly as raw code, because I like to have the option to compile with Freepascal and Lazarus.

My first test code for Oxygene Pascal with Webassembly as the target is thus very bare-bone. If there is something that has bugged me to no end, it’s that bloody HTML5 canvas. It’s a powerful thing, but it’s also overkill for per-pixel operations. So I figured that a nice, ad-hoc DIB (device independent bitmap) class will do wonders.

Note: Oxygene supports pointers, even under WebAssembly (!), but out of old habit I have avoided it. I want my code to compile for all the targets, without marking a class as “unsafe” in the dot-net paradigm. So I have avoided pointers and just use offsets instead.

namespace qtxlib;

interface

type

  // in-memory pixel format
  TPixelFormat = public (
      pf8bit  = 0,  //___8 -- palette indexed
      pf15bit = 1,  //_555 -- 15 bit encoded
      pf16bit = 2,  //_565 -- 16 bit encoded
      pf24bit = 3,  //_888 -- 24 bit native
      pf32bit = 4   //888A -- 32 bit native
      );

  TPixelBuffer = public class
  private
    FPixels:  array of Byte;
    FDepthLUT: array of Integer;
    FScanLUT: array of Integer;
    FStride:  Integer;
    FWidth:   Integer;
    FHeight:  Integer;
    FBytes:   Integer;
    FFormat:  TPixelFormat;
  protected
    function  CalcStride(const Value, PixelByteSize, AlignSize: Integer): Integer;
    function  GetEmpty: Boolean;
  public
    property  Width: Integer read FWidth;
    property  Height: Integer read FHeight;
    property  Stride: Integer read FStride;
    property  &Empty: Boolean read GetEmpty;
    property  BufferSize: Integer read FBytes;
    property  PixelFormat: TPixelFormat read FFormat;
    property  Buffer[const index: Integer]: Byte read (FPixels[&index]) write (FPixels[&index]);

    function  OffsetForPixel(const dx, dy: Integer): Integer;
    procedure Alloc(NewWidth, NewHeight: Integer; const PxFormat: TPixelFormat);
    procedure Release();

    function Read(Offset: Integer; ByteLength: Integer): array of Byte;
    procedure Write(Offset: Integer; const Data: array of Byte);

    constructor Create; virtual;

    finalizer;
    begin
      if not GetEmpty() then
        Release();
    end;
end;

TColorMixer = public class
end;

TPainter = public class
private
  FBuffer:    TPixelBuffer;
public
  property    PixelBuffer: TPixelBuffer read FBuffer;

  constructor Create(const PxBuffer: TPixelBuffer); virtual;
end;

implementation

//##################################################################################
// TPainter
//##################################################################################

constructor TPainter.Create(const PxBuffer: TPixelBuffer);
begin
  inherited Create();
  if PxBuffer  nil then
    FBuffer := PxBuffer
  else
    raise new Exception("Pixelbuffer cannot be NIL error");
end;

//##################################################################################
// TPixelBuffer
//##################################################################################

constructor TPixelBuffer.Create;
begin
  inherited Create();
  FDepthLUT := [1, 2, 2, 3, 4];
end;

function TPixelBuffer.GetEmpty: Boolean;
begin
  result := length(FPixels) = 0;
end;

function TPixelBuffer.OffsetForPixel(const dx, dy: integer): Integer;
begin
  if length(FPixels) > 0 then
  begin
    result := dy * FStride;
    inc(result, dx * FDepthLUT[FFormat]);
  end;
end;

procedure TPixelBuffer.Write(Offset: Integer; const Data: array of Byte);
begin
  for each el in Data do
  begin
    FPixels[Offset] := el;
    inc(Offset);
  end;
end;

function TPixelBuffer.Read(Offset: Integer; ByteLength: Integer): array of Byte;
begin
  result := new Byte[ByteLength];
  var xOff := 0;
  while ByteLength > 0 do
  begin
    result[xOff] := FPixels[Offset];
    dec(ByteLength);
    inc(Offset);
    inc(xOff);
  end;
end;

procedure TPixelBuffer.Alloc(NewWidth, NewHeight: Integer; const PxFormat: TPixelFormat);
begin
  if not GetEmpty() then
    Release();

  if NewWidth < 1 then
    raise new Exception("Invalid width error");

  if NewHeight  0 then
    result := ( (Result + AlignSize) - xFetch );
end;

end.

This code is just meant to give you a feel for the dialect. I have used a lot of “Delphi style” coding here, so chances are you will hardly see any difference bar namespaces and a funny looking property declaration.

Stay tuned for more posts as I explore the different aspects of Oxygene and webassembly in the days to come 🙂

  1. xepol
    June 12, 2019 at 6:58 pm

    Without a designer of some sort, it’s still just a half a solution. If they ever get that far, I will have investigate it as a Delphi alternative.

    • June 12, 2019 at 7:33 pm

      That depends very much on how you normally work. I havent used a designer in almost a decade. The reason is that when I do Delphi code, I always code everything manually so that I can also use FPC to target Linux out of the box. Most C/C++ developers likewise work that way. Visual Studio C/C++ is about as visual as a slice of bread.

      Having said that, there is a debate regarding layout management. Its not just webassembly involved here, but a whole host of targets – not all of them are absolute-position friendly. So something clever has to be setup.

      • xepol
        June 12, 2019 at 9:05 pm

        Frankly, coding VCL without a designer sounds like a massive waste of time. The designer is one of the major benefits of Delphi.

        If am working without a designer, I might as well be using C++, then I can target pretty much everything.

        And ya, the lack of a designer is a big big part of why I have had no use for RemObjects’ solutions so far, even if they have managed to push deep into the language and target multiple platforms.

        After all, if there isn’t a clear benefit, the best language to use is almost always the platform’s preference (Visual Studio, gcc), because most of the actual examples are there.

        I love object pascal, but it does not play nice with the rest of the world. Even python blows the doors off it when it comes to interacting with C++ code.

        So ya, something would need to exist to justify my investment in the learning curve, and a designer like Delphi *AND* Lazarus both have is a big, big part of that.

        After all, without it, I might as well actually be using a familiar editor and a command line compiler.

        Much as I wish I could benefit from RemObjects’ hard work, like you, I already have enough hard work of my own without make work projects.

        • June 30, 2019 at 5:00 pm

          Like I said, it comes down to how you are used to working. Sure, there are times when a designer makes perfect sense – Im sure i would have used a designer myself, if I was not forced to write platform independent code (before it was officially supported). The only way to do that prior to Elements, was to compile with freepascal. And the easiest way to make code work on both LCL and VCL, was to do the UI code manually.
          So there are reasons behind all this.

          In Smart Mobile Studio too I got used to working without a designer. Making custom-controls are second nature to me, and isolating aspects of an UI in visual and non-visual parts.

          Im not suggesting that everyone should just jump ship. Porting code is often a large task. RemObjects Hydra is a good middle-ground for people who want to organize their projects in DLL files, mixing and matching with dot-net, Java and delphi (for example).
          But starting a fresh project that should target all available platforms, including ARM 32/64 bit .. well, thats a good entrypoint to Oxygene

  2. Stefan Glienke
    June 12, 2019 at 8:21 pm

    To be honest this looks to me like desperately trying to appeal existing Delphi users and telling them “no problemo, you can use your existing code” while in fact it will fall apart as soon as you are using either VCL pieces that don’t exist or third party components.

    Where I agree though is that a good design separates the language/syntax from its runtime and the platforms as much as possible to not paint yourself into a corner – something that Delphi despite the growing number of supported platforms is still struggling with.

    • June 30, 2019 at 5:08 pm

      Oxygene as a language grew out of the Delphi community, so it’s hardly a desperate attempt. With the exception of the Freepascal community, Delphi is the only large-scale community where object-pascal is used — so naturally it will be tailored to meet demands from that group.

      I dont think anyone is saying that you can just take your Delphi project and re-compile it with Oxygene. That is not how this works. LIke you say, third party components wont exist – and the toolchain would need complete refactoring.

      The “VCL framework” for RemObjects is a bit like the Smart RTL, it’s there to deliver familiar classes and functionality – to help make people productive.

      You have to remember, that the VCL framework here is not just for Delphi or FPC developers. Its also for C#, Swift and Java developers.

      But hey, people have to pick the tools that works best for their toolbox. I compile more for JavaScript and ARM these days than anything else – and my toolkit has become optimized for that.

      Its all about options. You might not need this today, but at some point you might find our way of doing things a better fit.

  3. Cristiano Barbosa
    June 12, 2019 at 9:05 pm

    I would like to know how I can compile this code for webassembly and testing.

    it would be great to have a screencast doing the build for webassembly

    • June 30, 2019 at 5:01 pm

      You have to download Elements from the RemObjects website. There is a trial edition you can download, with the Water editor/IDE.

      Yes, ill see if i can do some youtube videos shortly 🙂

  4. cristiano gol sistemas
    June 12, 2019 at 10:24 pm

    If you are in Embarcadero, and with the experience you have in compiling pascal code for javascript, then Embarcadero will follow this path?

    • June 30, 2019 at 4:55 pm

      I dont work at Embarcadero any more, i quit a while back and signed up with RemObjects

  5. yogiyang007
    June 16, 2019 at 2:17 pm

    You have mentioned that coding without a Visual Designer is the way to go but I feel without a visual designer is like tying to hit the base ball with blind folds.

    I don’t totally agree with you here.

    You have mentioned:
    >>I always code everything manually so that I can also use FPC to target Linux out of the box

    I have still not seen any product that you have developed for multiple OSs and in FPC. Can you name something that you have coded in FPC and is working?

    • June 30, 2019 at 5:10 pm

      Most of my work is for companies. Not really named products that can be openly bought. I used FPC when porting some Win32 services to Linux a while back. I also compiled a native pixel buffer library to use with node.js — plenty of FPC code around 🙂

  1. No trackbacks yet.

Leave a reply to xepol Cancel reply