Archive

Archive for May, 2014

Emulating sets in Smart Mobile Studio

May 31, 2014 Leave a comment

Note: updated the article to also have code with unlimited set values (see bottom of page)

The Smart Mobile Studio compiler does not support sets. But there are ways to getting around that, as long as you can live with sets that has a maximum range of 32 elements. Here is a snippet from the QTX RTL which is being designed as I type. Here sets are solved as such:


type
TQTXValueSet = Record
  bsValue: Integer;
  function  contains(const aValue:Integer):Boolean;overload;
  Procedure Include(const aValue:Integer);
  Procedure Exclude(const aValue:Integer);
End;

//#############################################################################
// TQTXValueSet
//#############################################################################

function TQTXValueSet.Contains(const aValue:Integer):Boolean;
Begin
  result:=TInteger.getBit(aValue,bsValue);
end;

Procedure TQTXValueSet.Include(const aValue:Integer);
Begin
  TInteger.setBit(aValue,true,bsValue);
end;

Procedure TQTXValueSet.Exclude(const aValue:Integer);
Begin
  TInteger.setBit(aValue,false,bsValue);
end;

You can now do stuff like:

const
  csNone       = 0;
  csCreating   = 1;
  csDestroying = 2;

if not FMySet.contains(csCreating) then
FMySet.include(csCreating);

Neat ūüôā

Updated

It strikes me that, while the above method is by far the most cost-effective way to emulate sets – in that it will only consume one integer (4 bytes) of memory, it is neither the most flexible or faster variation on the theme. And in all honesty, worrying about memory consumption in a garbage collected script environment is more of an old habit of native languages than a real-life scenario.

As such, here is a faster version that supports an endless number of values I made using arrays.


TQTXValueSet = Record
  vsData: Array of Integer;
  function  Contains(const aSetValue:Integer):Boolean;
  Procedure Include(const aSetValue:Integer);
  Procedure Exclude(const aSetValue:Integer);
End;

//#############################################################################
// TQTXValueSet
//#############################################################################

function TQTXValueSet.Contains(const aSetValue:Integer):Boolean;
Begin
  result:=False;
  if vsData.count>0 then
  result:=vsData.IndexOf(aSetValue,vsData.Low)>=0;
end;

Procedure TQTXValueSet.Include(const aSetValue:Integer);
begin
  if not Contains(aSetValue) then
  vsData.Add(aSetValue);
end;

Procedure TQTXValueSet.Exclude(const aSetValue:Integer);
var
  mIndex: Integer;
begin
  mIndex:=vsData.IndexOf(aSetValue,vsData.low);
  if mIndex>=0 then
  vsData.delete(mIndex);
end;

Join the pascal for kids initiative!

May 27, 2014 1 comment

I am looking for a couple of good Delphi developers that would like to donate some spare time into an educational project for children. In short I am proposing that we all put some energy into a “pascal for kids” IDE and runtime, to help promote pascal as the friendly, powerful and flexible language we all know and love. In short the project aim’s to:

  • Provide and IDE which is suitable for children¬†age 10+
  • Implement a simple, easy to use and understand runtime library
  • Focus on easy and fast¬†visual feedback (games, perhaps simple maths)
  • Be capable of executing applications¬†primarily in the browser

What I propose is to introduce a free, easy to learn, easy to use pascal environment for children aged 10 and above. The focus should be on game creation (or more precise: graphical, sound and other creative expression) in order to stimulate interest in programming as a whole Рbut using pascal as the central language.

The project should in no way try to be “another Delphi”, nor should it compete in with freepascal or smart mobile. It should be simple (a reduced sub-set of pascal) and effective, with documentation and examples suitable for schools and local clubs.

It should not be for financial gain, so I cannot offer any money — and also it should be open source and free for all.

I hope some of my fellow Delphi and FPC programmers could help out. We need donations of many types, components for design/layout (painter component f.ex, for sprite design), mod music player code (bass or fdlib wrapper?) and also parser/compiler code.

Some background for the initiative

STOS basic sprite editor

STOS basic sprite editor

During the 90’s there was a small revolution when it came to programming. This was mainly due to the fact that home computers had reached a point where they were powerful enough to host intuitive and “modern” editors and compilers. Graphically they were powered by custom chipsets, much like the x-box and playstations today. And as such their graphical capabilities were far beyond anything a PC or Mac could muster at that price-range.

The result was that the Commodore Amiga and Atari ST completely dominated home computing, while PC’s and Mac’s were reduced to¬†business (PC) and design (Mac). Amiga and Atari were cheap, effective and suitable for both serious software and games – but for most kids and teenagers that grew up with an Amiga or Atari, games, music and creativity was the primary motivation for getting one.

Languages

Learning to program on the Amiga was very hard to begin with. About 90% of all software was either written in assembler or a hybrid language¬†called BCPL. Some serious business applications like word-processors and spreadsheets were written in C, but the Amiga did not get a decent ¬†C compiler until very late in its evolution – at which point PC’s had started to support powerful graphics cards and were slowly eroding the Amiga markedshare.

Amos basic IDE

Amos basic IDE

Around 1990 something changed the learning-curve, and that was the release of Amos basic. Amos was a flavour of basic designed for game programming. The features can be compared to SDL (Simple direct media layer) or Direct X, but with an easy to understand, easy to use basic dialect to access all that power.

The result was a whole generation of teenagers with a new-found interest in programming and game production. Games like Worms were actually created using Basic on the Amiga (blitzbasic, which superseded Amos). Many of the programmers that started on the Amiga work as professional developers today. What is now Sony Europe for example, used to be Psygnosis – a game company dedicated to Amiga game production.

Pascal

Today however, alternatives with the same amount of power. simplicity and friendliness is nearly non-existent. It is my belief that JavaScript has grown as popular as it has precisely because it was the only alternative for the generations that grew up after the Amiga was dead.¬†This generation quite frankly missed out on all the cool stuff we had on 16 bit computers. So where¬†programmers now in their 40’s had access to¬†a proper learning curve using¬†classical languages – kids today grow up with the browser as their main platform.

Scratch is a visual programming aid designed for kids

Scratch is a visual programming aid designed for kids

Pascal has everything. First of all it was designed for being taught in schools, secondly it has evolved side by side with C++ (CPP builder and Delphi has the same compiler core, with only a syntax module separating the products) and last but not least — it is more flexible and powerful than Basic.

I really think we can do better than basic. And I really want to see more kids learn pascal than javascript!

I also believe that systems like Scratch are helpful, but ultimately it will backfire because¬†typing and learning to express creativity as written logical structures will seem like a burden. The future will no doubt see better, visual programming tools — but i’m afraid quality will be lost and we will end up with a generation of bloat-ware

We can do better than this!

Commandline controller class

May 23, 2014 Leave a comment

While the occasions are rare, there are times when you have to isolate a piece of code in¬†a command line application. While Delphi makes it easy to work with the command line –¬†Embarcadero could have simplified it even more.

This is a small and effective command line controller class I wrote, that takes care of parsing parameters. Simply register your keywords with a callback procedure (anonymous of course) and voila — you can now spend your time handling options rather than parsing.

 


uses
  System.SysUtils, System.Generics.Collections;



  type

  TCMDLineController = Class(TObject)
  type
    ECMDLineController  = Class(Exception);
    TCMDLineCallback    = TProc;
  strict private
    FCommands:  TDictionary<string,tcmdlinecallback>;
  public
    Procedure   RegisterKeyword(aKeyword:String;
                const aHandler:TCMDLineCallback);virtual;
    Procedure   UnRegisterKeyword(aKeyword:String);virtual;
    Procedure   Process(Const UnknownTokenHandler:TProc);virtual;
    Constructor Create;virtual;
    Destructor  Destroy;Override;
  End;


//############################################################################
// TCMDLineController
//############################################################################

constructor TCMDLineController.Create;
begin
  inherited;
  FCommands:=TDictionary<string,tcmdlinecallback>.Create;
end;

destructor TCMDLineController.Destroy;
begin
  FCommands.Free;
  inherited;
end;

(* Purpose: Removes a keyword and callback handler from
            the commandline dictionary *)
Procedure TCMDLineController.UnRegisterKeyword(aKeyword:String);
Begin
  aKeyword:=lowercase(trim(aKeyword));
  if length(aKeyword)>0 then
  begin
    if FCommands.ContainsKey(aKeyword) then
    FCommands.Remove(aKeyword);
  end;
end;

(* Purpose: Registers a keyword and callback handler into
            the commandline controller dictionary.
            This means that whenever the controller encounters
            that keyword, the method will be called.

            In your code:
            ============

            registerKeyword('-option',
              procedure (value:String)
              begin
                showmessage('option value=' + Value);
              end );


            from the commandline:
            =====================

            >> mycommand.exe -option:someoption

            where "someoption" will be the value passed to
            your callback procedure
            *)
Procedure TCMDLineController.RegisterKeyword(aKeyword:String;
          const aHandler:TCMDLineCallback);
const
  CNT_ERR_KeywordExists =
  'Invalid commandline keyword error, keyword already exists';

  CNT_ERR_CallbackNIL =
  'Invalid commandline callback error, entrypoint was NIL';

  CNT_ERR_KeywordEmpty =
  'Invalid commandline keyword error, keyword was empty';
begin
  aKeyword:=lowercase(trim(aKeyword));
  if length(aKeyword)>0 then
  begin
    if assigned(aHandler) then
    begin
      if not FCommands.ContainsKey(aKeyword) then
      FCommands.Add(aKeyword,aHandler) else
      raise ECMDLineController.Create(CNT_ERR_KeywordExists);
    end else
    raise ECMDLineController.Create(CNT_ERR_CallbackNIL);
  end else
  Raise ECMDLineController.Create(CNT_ERR_KeywordEmpty);
end;

(* Purpose: Process the commandline parameters and match
            the values with our dictionary.
            If a keyword is not found, the unknownTokenHandler() procedure
            is called with the unknown keyword.
            Otherwise the callback handler installed for that keyword
            is called, with the value text defined for the param.

            E.g:
              mycmd.exe -somecommand:somevalue

            where -somecommand is the keyword, and somevalue is the
            string passed to the callback handler.
            The ":" character is used as a fixed separator.
            *)
procedure TCMDLineController.Process(const UnknownTokenHandler: TProc);
var
  x:  Integer;
  xpos: Integer;
  mtext:  String;
  mName:  String;
  mValue: String;
begin
  for x:=1 to System.ParamCount do
  begin
    mtext:=System.ParamStr(x);
    xpos:=pos(':',mText);
    if xpos>0 then
    begin
      mName:=copy(mtext,1,xpos-1);
      mValue:=copy(mtext,xpos+1,length(mText));
      if FCommands.ContainsKey(mName) then
      FCommands[mName](mValue) else
      if assigned(UnknownTokenHandler) then
      UnknownTokenHandler(mText);
    end else
    if assigned(UnknownTokenHandler) then
    UnknownTokenHandler(mText);
  end;
end;

Using the controller

Using the class is easy. Simply create an instance, register your keywords and callback handlers – and call process. Here is a small example of how you can use it:

  Controller:=TCMDLineController.Create;
  try

    Controller.RegisterKeyword('-input',
      procedure (aValue:String)
      begin
        writeln('Input Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-rtl',
      procedure (aValue:String)
      begin
        writeln('RTL Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-output',
      procedure (aValue:String)
      begin
        writeln('Output Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-mode',
      procedure (aValue:String)
      begin
        writeln('Mode Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-gen',
      procedure (aValue:String)
      begin
        writeln('Gen Param set to:' + aValue);
      end);

    Controller.RegisterKeyword('-help',
      procedure (aValue:String)
      begin
        DisplayHelp;
      end);

    //Now process and handle unknown keywords
    Controller.Process(procedure (aValue:String)
      Begin
        writeln('unknown keyword:' + aValue);
        DisplayHelp;
      end);

  finally
    Controller.Free;
  end;