I am starting to tinker (again!) with Free Pascal and Lazarus.
Here is the start of a collection of things I started with, that I talk about more below: https://gitlab.com/bolsen80/pascalhttptests.
I got motivated once after reading something on Hacker News last year. I think it started with something related to compliation speed. This piqued my own interest again, since this was the first programming language I seriously had to learn, like many teenagers in the US taking AP Computer Science during the 1990s and earlier. While I was not exactly a star-student in that class, the impression of it stuck with me. Pascal always seemed to me a clean, if rigourous language to use. The 'declare all variables at the top' thing had a bit of an impact and stuff for thought. It's little things like that which probably assist in the compiler being able to build so quickly also.
Last year, I did an experiment to make a toy version of the CLI client for my former company's API, but then set things aside for awhile. But I want to get back to it. I am treating it like a toy: I want to do stuff with it (and I mention below) but as with any side project, I am not necessarily committed to anything.
Pascal is a "dead" language, mentioned in one way or another on Hacker News and other places. Certainly not going to argue that, but the Free Pascal compiler and resultant output is extremely good. FPC targets a lot of processors. It's completely independent from GCC or LLVM toolchains (maybe this is a good thing?) It can do things that C does, probably without making it easy to shoot yourself in the foot. I mean, in the 80s, it was used to write OSs like Classic Mac OS, I think System 6 and below (I remember printing out the Pascal documentation for the Macintosh Toolbox, thinking I would actually write Pascal programs for my Mac at the time by just gleaning what was effectively API documentation only :P ) I also know it has a good FFI (the compiler uses a different ABI, but I don't much about that). FreePascal also has nostalgia points for having a text editor reminicent of Turbo Pascal's editor for MS-DOS, but I doubt I'd ever use it, other than reliving me struggling to figure out how to program on the school computer.
When it comes down to it though, can I be honest to say that C still scares me? :) It assumes first you will be juggling pointers; by default, it will copy-by-value. Pascal defaults to copy-by-reference. This completely shifts the interfaces you work with since it doesn't start with thinking about properly dealing with pointers. It's not like it is intractable in C, but Pascal seems like a systems programming language that is actually approachable to application developers. Syntactically also, it feels comfortable to read. It's a very rigourous language and I expect and language with quirks to be a pain to deal with (like Python and its indentation.) I read one complaint that it is easy to get varlist of declarations too long for certain things. But, there is always trade-offs.
Also, I like semi-obscure things like this. Pascal however, was not obscure, just lost in the market to the likes of other language environments, like Java or .NET. I am taking this as an experience on what I could be missing from my current knowledge, outside the slog of learning hot new tech (just not that interested now in a side project creating another JavaScript UI with a terabyte worth of node libraries to show text in a browser or putting up with weird TypeScript type puzzles ... (TypeScript was actually started by the one who wrote Turbo Pascal and then C#, so there are influences in both from Pascal.) I am not expecting Pascal to be a replacement for everything that a "backend" developer expects (If you know me, you know what I think about the "frontend"/"backend" moniker - the term didn't exist until after people wanted to become masochists (unfortunately I was one of them! and probably will still do so) with JavaScript toolchains :P )
It's also nice I learned a thing that was different than C's default mode of memory management. In terms of manual memory management, there is some interesting things to note. This is what made me think "oh, this sounds like Rust!". If a class subclasses TComponent
, it gets a ownership-style memory management model. A lot of the FCL and LCL (FreePascal/Lazarus Component Library) uses this.
An example:
TName = class(TComponent)
public
First: string;
Last: string;
destructor Destroy; override;
end;
TPerson = class(TComponent)
private
FName: TName;
FAge: Integer;
procedure SetName(Value: TName);
procedure SetAge(Value: Integer);
public
property Name: TName read FName write SetName;
property Age: Integer read FAge write SetAge;
destructor Destroy; override;
end;
(these are just the headers, not going to implement them.) However, you can do this (it might not be perfect, I am still learning):
var
Name: TName;
Person: TPerson;
begin
try
Person := TPerson.Create(nil);
Name := TName.Create(Person);
Name.First := 'Brian';
Name.Last := 'Olsen';
Person.Name := Name;
Person.Age := 42;
finally
FreeAndNil(Person); // RIGHT here
end;
end.
If you declare child objects as owned by other TComponent
objects, when you call FreeAndNil()
, it will properly handle the child object cleanup. (I am not familiar with C++, but I read that destructor semantics are similar to what is in C++.) I think but I am not sure but it can be true that the TComponent
and FreeAndNil()
also is thread-safe. I think this is interesting and something I am going to be aware of as I go further. This is probably not what completely what Rust does. When I started to study Rust, ownership and "borrowing" seemed complex to get. It might be safer in the end, but there is a mental leap to take to get one's head around this system. For me, it's not knowing why I would do some things. The why around TComponent
just made sense after reading a couple of paragraphs about it.
What was a bit of a friction at first (me being very lazy and just expect things to be intuitive):
This highlights something - a programming language's value is in its toolchain. I would like to have tools to solve problems close to my fingers, primarily ones that are available on the CLI or in Emacs. As said, though, Lazarus is good for discovery, but running to the mouse for things is not a long-term plan to dig up a function for any language for me.
I wiil discuss probably the best entry point to get the toolchain and then go into talk about LSP.
I want to say that I have no experience with Delphi nor do I want to use that. I saw it was too expensive and Embarcadero seems to only be interested in squeezing out as much money as possible from customers with it. Borland and then Embarcadero have been described as failing to really prepare Pascal for the age of web development. Lazarus is an opt name, of course, because it was Lazarus in the Bible who came back from death. As such, Lazarus (the IDE) is probably not exactly like current Delphi, but it is probably close. Also, FreePascal, implements changes in Delphi Pascal.
https://github.com/LongDirtyAnimAlf/fpcupdeluxe
It is a GUI that allows one to install a whole toolchain, which I would guess in normal cases, would be both FPC and Lazarus.
There are two versions, the "plain" one (which uses GTK2) and the Qt5 version. It's a detailed I completely missed, because one thing to note is that Lazarus uses the desktop environment's theme settings for all of its windows. The first builds, unknowingly using the GTK2 version, resulted in Lazarus stuck in the default light-mode ... I don't like staring into lightbulbs and I don't like blinding screens :) The only thing that is configurable in the IDE is the text editor. (I use KDE, which is Qt-based.)
So, finding this one out in the FreePascal forum that it's best to get the correct version of fpcupdeluxe and getting the Qt5 version (also after a sudo apt install libqt5pas-dev
) solved that problem.
I would recommend to click on "Setup +" and checking "Docked Lazarus IDE". The plugin in Lazarus is called anchordockeddsgn
and can also be installed by going to "Packages > Install/Uninstall Packages". When you install a plugin, you then rebuild the IDE.
It's fascinating that the IDE has to be rebuilt, even for other non-IDE related packages. The IDE itself becomes a part of the wider package install. It has a Smalltalk-y or Emacs-y feel to it, but specifically that IDE + language are part of the same sphere.
The very first ergonomic for me is if I can use it in Emacs. LSP (Language Server Protocol, started by Microsoft) is a real game changer, in that you can provide IDE-level tooling into text editors. MS's intent was to target VSCode first, but other people supported their favorite text editors, like in Emacs with lsp-mode
.
LSP is a client-server architecture: the plugin is the client, the server is the one that does completions/lookups/etc. in the language runtime, using etags or code analysis API.
When I started, there was a start of a project for an LSP Pascal: https://github.com/arjanadriaanse/pascal-language-server but it wouldn't do certain things right. In this new burst of inspiration, I found a lot of notes around it: https://github.com/michaliskambi/elisp/tree/master/lsp ... The author wrote an excellent introduction to Modern Object Pascal as part of his documentation on his Game Engine written in Free Pascal: https://castle-engine.io/modern_pascal. (I recommend to read that if you happen to be interested in toying with Pascal.
There are now 3 forks of that project that I tried: 1. https://github.com/Isopod/pascal-language-server 2. https://github.com/genericptr/pascal-language-server 3. https://github.com/castle-engine/pascal-language-server
(The third one forks the first one :) )
It seemed like getting any of them to work was a chore. Each one did better than the first version, but when it came to completions, it was not working for me. The issue however, was a configuration issue, as highlighted clearly (but ignored fully by me) in this very thorough explanation in the link above setting up Emacs with a server.
These are my own settings in Emacs:
;; choose LSP server binary
;; (setq lsp-pascal-command "/home/bolsen/pascal/pascal-language-server/server/lib/x86_64-linux/pasls")
(setq lsp-pascal-command "/home/bolsen/pascal/pascal-language-server/server/pasls")
;; pass basic info to LSP server, all LSP Pascal servers above support these:
(setq lsp-pascal-pp "/home/bolsen/pascal/fpcup/fpc/bin/x86_64-linux/fpc.sh")
(setq lsp-pascal-fpcdir "/home/bolsen/pascal/fpcup/fpcsrc")
(setq lsp-pascal-lazarusdir "/home/bolsen/pascal/fpcup/lazarus")
(setq lsp-pascal-fpctarget "linux")
(setq lsp-pascal-fpctargetcpu "x86_64")
The problem was: (setq lsp-pascal-pp "/home/bolsen/pascal/fpcup/fpc/bin/x86_64-linux/fpc.sh")
... Just pointed to fpc
binary instead of the script. I didn't see the relevance until I saw what the fpc.sh
script did:
/home/bolsen/pascal/fpcup/fpc/bin/x86_64-linux/fpc -n @/home/bolsen/pascal/fpcup/fpc/bin/x86_64-linux/fpc.cfg "$@"
The fpc.cfg
file is generated by fpcmkcfg
. It writes a default list of command-line flags for the fpc
compiler along with a series of flags to point to where libraries are. I learned this trying to compile other things and getting errors that it couldn't find the unit system
.
Now I see this thing work, it motivated me to write this blog post :)
As an aside, Emacs has two pascal modes: pascal-mode
and opascal-mode
. By default, a number of the files that one would use (.lpr
, .pas
, etc.) default to pascal-mode
. I use this:
(add-to-list 'auto-mode-alist
'("\\.\\(pas\\|lpr\\)\\'" . opascal-mode))
pascal-mode
only implements pre-Object Pascal, which is probably only interesting for academic purposes. That's the Pascal I originally learned, not the one with classes, etc.
Now that I think I am in a good position (there are other things I want to fix though to make Emacs good for Pascal development, I want to go back to what I think I'll do next. I don't like trying things without a plan. These are some ideas I had. This is stuff to write about to when I can:
fpc-web
seems to be a first point of contact here. There are other frameworks, but this seems the easiest to start with. What seemed lacking though was a cookbook of things you can do with it, particularly on what they describe as the "preferred and new solution" https://wiki.freepascal.org/fpWebTutorial#NewMechanism. I think tooling like this needs goals, and it would be good to answer those things:
fptemplate
, to look into.)Location
header, but nice APIs are nice :))fp-web
actually.)fpjson
is something that I comfortably used in my API client toy)My thought is to make a MkDocs site primarily for my own use, but will publish here eventually.
Secondly, maybe at some point, I want to evalute the "Old Mechanism". While not encouraged, it was a bit more IDE-centric: you have for each Pascal unit a form-like file (an .lfm
file, like the same with a GUI designer file in Lazarus) which mapped routes to methods in handler classes. People have been moving away a lot from GUI-centric development and more code-centric (like Java moving away from XML configs to Java annotations).
A specific thing I thought of was to rewrite my blog and maybe solve the design issues when I started writing it last year as well.
Address some UX issues:
I don't have any GUI ideas really, which is the "killer app" here.
With FPC and Lazarus set up from fpcupdeluxe
and the binaries added to PATH
:
export PATH=$PATH:$HOME/pascal/fpcup/fpc/bin/x86_64-linux:$HOME/pascal/fpcup/lazarus
(I changed the default install path), I create a file called TestServer.lpr
and add this:
program TestServer;
{$mode objfpc}{$H+}
uses
{$ifdef UNIX}
cthreads, cmem,
{$endif}
fphttpapp,
httpdefs,
httproute;
procedure route1(aReq: TRequest; aResp: TResponse);
begin
aResp.Content := '<html><body><h1>Route 1 The Default</h1></body></html>';
end;
procedure route2(aReq: TRequest; aResp: TResponse);
begin
aResp.Content := '<html><body><h1>Route 2</h1></body></html>';
end;
begin
HTTPRouter.RegisterRoute('/', @route1, True);
HTTPRouter.RegisterRoute('/route2', @route2);
Application.Port:=8080;
Application.Threaded:=true;
Application.Initialize;
Application.run;
end.
The Application
actually is a singelton in the httproute
unit (basically a "module") of type THTTPApplication
:
Var
Application : THTTPApplication;
ShowCleanUpErrors : Boolean = False;
Compiling this with lazbuild TestServer.lpr
will produce a single binary (2.4 MB for me, though not fully self-contained, since it requires glibc
that it was compiled against.) Despite that, it would seem really nice for with Docker images running something like Alpine Linux. By default, Alpine uses musl
libc, but I think this is something that is solved (for example: https://wiki.lazarus.freepascal.org/Docker_Containerization.
If you made it down here, bravo! :) Will add more as I go along.
Made with Bootstrap and my site generator script.